diff --git a/MapleLib/WzLib/Util/WzBinaryReader.cs b/MapleLib/WzLib/Util/WzBinaryReader.cs index 7016b223..f76c4621 100644 --- a/MapleLib/WzLib/Util/WzBinaryReader.cs +++ b/MapleLib/WzLib/Util/WzBinaryReader.cs @@ -40,6 +40,23 @@ public WzBinaryReader(Stream input, byte[] WzIv) #endregion #region Methods + /// + /// Sets the base stream position to the header FStart + offset + /// + /// + public void SetOffsetFromFStartToPosition(int offset) + { + BaseStream.Position = Header.FStart + offset; + } + + public void RollbackStreamPosition(int byOffset) + { + if (BaseStream.Position < byOffset) + throw new Exception("Cant rollback stream position below 0"); + + BaseStream.Position -= byOffset; + } + public string ReadStringAtOffset(long Offset) { return ReadStringAtOffset(Offset, false); diff --git a/MapleLib/WzLib/Util/WzBinaryWriter.cs b/MapleLib/WzLib/Util/WzBinaryWriter.cs index 0e0e4d88..fbbe9724 100644 --- a/MapleLib/WzLib/Util/WzBinaryWriter.cs +++ b/MapleLib/WzLib/Util/WzBinaryWriter.cs @@ -14,9 +14,11 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * You should have received a copy of the GNU General Public License along with this program. If not, see .*/ +using System; using System.Collections; using System.IO; using MapleLib.MapleCryptoLib; +using MapleLib.WzLib.WzStructure.Enums; namespace MapleLib.WzLib.Util { @@ -59,10 +61,12 @@ public WzBinaryWriter(Stream output, byte[] WzIv, bool leaveOpen) /// ?InternalSerializeString@@YAHPAGPAUIWzArchive@@EE@Z /// /// - /// 0x73 - /// 0x1B + /// bExistID_0x73 0x73 + /// bNewID_0x1b 0x1B public void WriteStringValue(string s, int withoutOffset, int withOffset) { + // if length is > 4 and the string cache contains the string + // writes the offset instead if (s.Length > 4 && StringCache.ContainsKey(s)) { Write((byte)withOffset); @@ -80,24 +84,37 @@ public void WriteStringValue(string s, int withoutOffset, int withOffset) } } - public void WriteWzObjectValue(string s, byte type) + /// + /// Writes the Wz object value + /// + /// + /// + /// + /// true if the Wz object value is written as an offset in the Wz file, else if not + public bool WriteWzObjectValue(string stringObjectValue, WzDirectoryType type) { - string storeName = string.Format("{0}_{1}", type, s); - if (s.Length > 4 && StringCache.ContainsKey(storeName)) + string storeName = string.Format("{0}_{1}", (byte) type, stringObjectValue); + + // if length is > 4 and the string cache contains the string + // writes the offset instead + if (stringObjectValue.Length > 4 && StringCache.ContainsKey(storeName)) { - Write((byte)2); + Write((byte)WzDirectoryType.RetrieveStringFromOffset_2); // 2 Write((int)StringCache[storeName]); + + return true; } else { int sOffset = (int)(this.BaseStream.Position - Header.FStart); - Write(type); - Write(s); + Write((byte)type); + Write(stringObjectValue); if (!StringCache.ContainsKey(storeName)) { StringCache[storeName] = sOffset; } } + return false; } public override void Write(string value) diff --git a/MapleLib/WzLib/WzDirectory.cs b/MapleLib/WzLib/WzDirectory.cs index 935c150e..81a54be8 100644 --- a/MapleLib/WzLib/WzDirectory.cs +++ b/MapleLib/WzLib/WzDirectory.cs @@ -230,6 +230,7 @@ internal void ParseDirectory(bool lazyParse = false) } default: { + reader.PrintHexBytes(20); throw new Exception("[WzDirectory] Unknown directory. type = " + type); } } diff --git a/MapleLib/WzLib/WzFile.cs b/MapleLib/WzLib/WzFile.cs index 683e1913..94778f0b 100644 --- a/MapleLib/WzLib/WzFile.cs +++ b/MapleLib/WzLib/WzFile.cs @@ -40,15 +40,16 @@ public class WzFile : WzObject internal WzDirectory wzDir; internal WzHeader header; internal string name = ""; + internal ushort wzVersionHeader = 0; internal const ushort wzVersionHeader64bit_start = 770; // 777 for KMS, GMS v230 uses 778.. wut + internal uint versionHash = 0; internal short mapleStoryPatchVersion = 0; internal WzMapleVersion maplepLocalVersion; internal MapleStoryLocalisation mapleLocaleVersion = MapleStoryLocalisation.Not_Known; - internal bool b64BitClient = false; // KMS update after Q4 2021, ver 1.2.357 - internal bool b64BitClient_withVerHeader = false; // + internal bool wz_withEncryptVersionHeader = true; // KMS update after Q4 2021, ver 1.2.357 internal byte[] WzIv; #endregion @@ -102,7 +103,7 @@ public override WzObjectType ObjectType /// public MapleStoryLocalisation MapleLocaleVersion { get { return mapleLocaleVersion; } private set { } } - public bool Is64BitWzFile { get { return b64BitClient; } private set { } } + public bool Is64BitWzFile { get { return !wz_withEncryptVersionHeader; } private set { } } public override WzObject Parent { get { return null; } internal set { } } @@ -166,9 +167,6 @@ public WzFile(string filePath, short gameVersion, WzMapleVersion version) } else this.WzIv = WzTool.GetIvByMapleVersion(version); - - string[] filePathSplit = Regex.Split(filePath, @"\\"); - this.b64BitClient = filePathSplit.Contains("Data"); // TODO: Find a better way of identifying 64-bit client/ WZ from the WZ files instead. This might break if it isnt installed in the right path, esp. private servers } /// @@ -183,8 +181,6 @@ public WzFile(string filePath, byte[] wzIv) maplepLocalVersion = WzMapleVersion.CUSTOM; this.WzIv = wzIv; - - this.b64BitClient = false; // TODO } /// @@ -235,15 +231,15 @@ internal WzFileParseStatus ParseMainWzDirectory(bool lazyParse = false) // the value of wzVersionHeader is less important. It is used for reading/writing from/to WzFile Header, and calculating the versionHash. // it can be any number if the client is 64-bit. Assigning 777 is just for convenience when calculating the versionHash. - this.wzVersionHeader = b64BitClient && !b64BitClient_withVerHeader ? wzVersionHeader64bit_start : reader.ReadUInt16(); + this.wzVersionHeader = this.wz_withEncryptVersionHeader ? reader.ReadUInt16() : wzVersionHeader64bit_start; if (mapleStoryPatchVersion == -1) { // for 64-bit client, return immediately if version 777 works correctly. // -- the latest KMS update seems to have changed it to 778? 779? - if (b64BitClient) + if (!this.wz_withEncryptVersionHeader) { - for (ushort maplestoryVerToDecode = wzVersionHeader64bit_start; maplestoryVerToDecode < wzVersionHeader64bit_start + 20; maplestoryVerToDecode++) + for (ushort maplestoryVerToDecode = wzVersionHeader64bit_start; maplestoryVerToDecode < wzVersionHeader64bit_start + 10; maplestoryVerToDecode++) // 770 ~ 780 { if (TryDecodeWithWZVersionNumber(reader, wzVersionHeader, maplestoryVerToDecode, lazyParse)) { @@ -290,40 +286,40 @@ private void Check64BitClient(WzBinaryReader reader) { if (this.Header.FSize >= 2) { - this.wzVersionHeader = reader.ReadUInt16(); - if (this.wzVersionHeader > 0xff) + reader.BaseStream.Position = this.header.FStart; // go back to 0x3C + + int encver = reader.ReadUInt16(); + if (encver > 0xff) // encver always less than 256 { - b64BitClient = true; + this.wz_withEncryptVersionHeader = false; } - else if (this.wzVersionHeader == 0x80) + else if (encver == 0x80) { - // there's an exceptional case that the first field of data part is a compressed int which determines the property count, + // there's an exceptional case that the first field of data part is a compressed int which determined property count, // if the value greater than 127 and also to be a multiple of 256, the first 5 bytes will become to - // 80 00 xx xx xx - // so we additional check the int value, at most time the child node count in a WzFile won't greater than 65536 (0xFFFF). + // 80 00 xx xx xx + // so we additional check the int value, at most time the child node count in a wz won't greater than 65536. if (this.Header.FSize >= 5) { reader.BaseStream.Position = this.header.FStart; // go back to 0x3C - int propCount = reader.ReadCompressedInt(); - if (propCount > 0 && (propCount & 0xFF) == 0 && propCount <= 0xFFFF) + int propCount = reader.ReadInt32(); + if (propCount > 0 && (propCount & 0xff) == 0 && propCount <= 0xffff) { - b64BitClient = true; + this.wz_withEncryptVersionHeader = false; } } - } else if (this.wzVersionHeader == 0x21) // or 33 + } else { - b64BitClient = true; - // but read the header - // the latest KMS seems to include this back in again.. damn - this.b64BitClient_withVerHeader = true; // ugly hack, but until i've found a better way without breaking compatibility of old WZs. + // old wz file with header version } } else { - // Obviously, if data part have only 1 byte, encVer must be deleted. - b64BitClient = true; + // Obviously, if data part have only 1 byte, encver must be deleted. + this.wz_withEncryptVersionHeader = false; } + // reset position reader.BaseStream.Position = this.Header.FStart; } @@ -587,7 +583,7 @@ public void SaveToDisk(string path, bool? override_saveAs64BitWZ, WzMapleVersion // MapleStory UserKey bool bIsWzUserKeyDefault = MapleCryptoConstants.IsDefaultMapleStoryUserKey(); // check if its saving to the same UserKey. // Save WZ as 64-bit wz format - bool bSaveAs64BitWZ = override_saveAs64BitWZ != null ? (bool)override_saveAs64BitWZ : b64BitClient; + bool bWZ_withEncryptVersionHeader = this.wz_withEncryptVersionHeader; CreateWZVersionHash(); wzDir.SetVersionHash(versionHash); @@ -605,7 +601,7 @@ public void SaveToDisk(string path, bool? override_saveAs64BitWZ, WzMapleVersion { wzWriter.Hash = versionHash; - uint totalLen = wzDir.GetImgOffsets(wzDir.GetOffsets(Header.FStart + (bSaveAs64BitWZ && !this.b64BitClient_withVerHeader ? 0 : 2u))); + uint totalLen = wzDir.GetImgOffsets(wzDir.GetOffsets(Header.FStart + (bWZ_withEncryptVersionHeader ? 2u: 0))); Header.FSize = totalLen - Header.FStart; for (int i = 0; i < 4; i++) { @@ -620,7 +616,7 @@ public void SaveToDisk(string path, bool? override_saveAs64BitWZ, WzMapleVersion { wzWriter.Write(new byte[(int)extraHeaderLength]); } - if (!bSaveAs64BitWZ || this.b64BitClient_withVerHeader) + if (bWZ_withEncryptVersionHeader) wzWriter.Write(wzVersionHeader); wzWriter.Header = Header; diff --git a/MapleLib/WzLib/WzStructure/MapInfo.cs b/MapleLib/WzLib/WzStructure/MapInfo.cs index ecb17f4b..786adf81 100644 --- a/MapleLib/WzLib/WzStructure/MapInfo.cs +++ b/MapleLib/WzLib/WzStructure/MapInfo.cs @@ -310,7 +310,7 @@ public MapInfo(WzImage image, string strMapName, string strStreetName, string st fs = InfoTool.GetFloat(prop); break; case "protectItem": - protectItem = InfoTool.GetInt(prop); + protectItem = InfoTool.GetInt(prop); // could also be a WzSubProperty in later versions. "Map002.wz\\Map\\Map2\\211000200.img\\info\\protectItem" break; case "createMobInterval": createMobInterval = InfoTool.GetInt(prop); diff --git a/MapleLib/WzSettings.cs b/MapleLib/WzSettings.cs index 12aa2d9a..85835ec4 100644 --- a/MapleLib/WzSettings.cs +++ b/MapleLib/WzSettings.cs @@ -15,18 +15,11 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the along with this program. If not, see .*/ using System; -using MapleLib.WzLib.WzProperties; using System.Reflection; -using MapleLib.WzLib.WzStructure; using System.IO; using Newtonsoft.Json.Linq; using System.Drawing; -using System.Collections; using Newtonsoft.Json; -using Spine; -using System.Security.Principal; -using Microsoft.Xna.Framework.Media; -using System.Windows.Controls; namespace MapleLib.WzLib {