From a49710e366eaf6acaebdb1304b3b14feee7d9b08 Mon Sep 17 00:00:00 2001 From: morkt Date: Thu, 14 Sep 2023 19:07:00 +0400 Subject: [PATCH] (ReadCString): support UTF-16 encoding. --- GameRes/ArcView.cs | 11 ++++++--- GameRes/BinaryStream.cs | 40 ++++++++++++++++++++++++------- Legacy/Properties/AssemblyInfo.cs | 4 ++-- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/GameRes/ArcView.cs b/GameRes/ArcView.cs index 59a04d08..d1a26bac 100644 --- a/GameRes/ArcView.cs +++ b/GameRes/ArcView.cs @@ -42,6 +42,13 @@ namespace GameRes encoding.DecoderFallback = DecoderFallback.ExceptionFallback; return encoding; } + + public static bool IsUtf16 (this Encoding enc) + { + // enc.WindowsCodePage property might throw an exception for some encodings, while + // CodePage is just a direct field access. + return (enc.CodePage == 1200 || enc.CodePage == 1201); // enc is UnicodeEncoding + } } public static class StreamExtension @@ -440,9 +447,7 @@ namespace GameRes { byte* s = m_mem + (offset - m_offset); uint string_length = 0; - // enc.WindowsCodePage property might throw an exception for some encodings, while - // CodePage is just a direct field access. - if (enc.CodePage == 1200 || enc.CodePage == 1201) // for UTF-16 encodings stop marker is 2-bytes long + if (enc.IsUtf16()) // for UTF-16 encodings stop marker is 2-bytes long { ushort* u = (ushort*)s; while (string_length + 1 < size && 0 != u[string_length >> 1]) diff --git a/GameRes/BinaryStream.cs b/GameRes/BinaryStream.cs index 3a7ca08b..905ffc12 100644 --- a/GameRes/BinaryStream.cs +++ b/GameRes/BinaryStream.cs @@ -589,14 +589,13 @@ namespace GameRes public string ReadCString (int length, Encoding enc) { - length = Math.Min (length, m_length - m_position); int start = m_start+m_position; - int i = Array.IndexOf (m_source, 0, start, length); - if (-1 == i) - i = start+length; - string s = enc.GetString (m_source, start, i-start); + length = Math.Min (length, m_length - m_position); + int eos_pos = FindEoS (start, length, enc); + if (-1 == eos_pos) + eos_pos = start+length; m_position += length; - return s; + return enc.GetString (m_source, start, eos_pos-start); } public string ReadCString () @@ -607,17 +606,19 @@ namespace GameRes public string ReadCString (Encoding enc) { int start = m_start+m_position; - int eos_pos = Array.IndexOf (m_source, 0, start, m_length-m_position); + int length = m_length-m_position; + int eos_pos = FindEoS (start, length, enc); int count; if (-1 == eos_pos) { - count = m_length - m_position; + count = length; m_position = m_length; } else { count = eos_pos - start; - m_position += count + 1; + int eos_size = enc.IsUtf16() ? 2 : 1; + m_position += count + eos_size; } return enc.GetString (m_source, start, count); } @@ -631,6 +632,27 @@ namespace GameRes return buffer; } + internal int FindEoS (int start, int length, Encoding enc) + { + int eos_pos = -1; + if (enc.IsUtf16()) + { + for (int i = start+1; i < start+length; i += 2) + { + if (m_source[i-1] == 0 && m_source[i] == 0) + { + eos_pos = i - 1; + break; + } + } + } + else + { + eos_pos = Array.IndexOf (m_source, 0, start, length); + } + return eos_pos; + } + #region IO.Stream Members public override bool CanRead { get { return true; } } public override bool CanSeek { get { return true; } } diff --git a/Legacy/Properties/AssemblyInfo.cs b/Legacy/Properties/AssemblyInfo.cs index 4e50c303..d63b355a 100644 --- a/Legacy/Properties/AssemblyInfo.cs +++ b/Legacy/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion ("1.0.10.207")] -[assembly: AssemblyFileVersion ("1.0.10.207")] +[assembly: AssemblyVersion ("1.0.10.208")] +[assembly: AssemblyFileVersion ("1.0.10.208")]