internal WzPngProperty(WzBinaryReader reader, bool parseNow) { // Read compressed bytes width = reader.ReadCompressedInt(); height = reader.ReadCompressedInt(); format = reader.ReadCompressedInt(); format2 = reader.ReadByte(); reader.BaseStream.Position += 4; offs = reader.BaseStream.Position; int len = reader.ReadInt32() - 1; reader.BaseStream.Position += 1; if (len > 0) { if (parseNow) { compressedBytes = wzReader.ReadBytes(len); ParsePng(); } else { reader.BaseStream.Position += len; } } wzReader = reader; }
/// <summary> /// BPS of the mp3 file /// </summary> //public byte BPS { get { return bps; } set { bps = value; } } /// <summary> /// Creates a WzSoundProperty with the specified name /// </summary> /// <param name="name">The name of the property</param> /// <param name="reader">The wz reader</param> /// <param name="parseNow">Indicating whether to parse the property now</param> public WzSoundProperty(string name, WzBinaryReader reader, bool parseNow) { this.name = name; wzReader = reader; reader.BaseStream.Position++; //note - soundDataLen does NOT include the length of the header. soundDataLen = reader.ReadCompressedInt(); len_ms = reader.ReadCompressedInt(); long headerOff = reader.BaseStream.Position; reader.BaseStream.Position += soundHeader.Length; //skip GUIDs int wavFormatLen = reader.ReadByte(); reader.BaseStream.Position = headerOff; header = reader.ReadBytes(soundHeader.Length + 1 + wavFormatLen); ParseHeader(); //sound file offs offs = reader.BaseStream.Position; if (parseNow) { mp3bytes = reader.ReadBytes(soundDataLen); } else { reader.BaseStream.Position += soundDataLen; } }
//public byte BPS { get { return bps; } set { bps = value; } } /// <summary> /// BPS of the mp3 file /// Creates a WzSoundProperty with the specified name /// </summary> /// <param name="name">The name of the property</param> /// <param name="reader">The wz reader</param> /// <param name="parseNow">Indicating whether to parse the property now</param> public WzSoundProperty(string name, WzBinaryReader reader, bool parseNow) { this.Name = name; _wzReader = reader; reader.BaseStream.Position++; //note - soundDataLen does NOT include the length of the header. _soundDataLen = reader.ReadCompressedInt(); // 时间 _time = reader.ReadCompressedInt(); var headerOff = reader.BaseStream.Position; reader.BaseStream.Position += SoundHeader.Length; //skip GUIDs int wavFormatLen = reader.ReadByte(); reader.BaseStream.Position = headerOff; reader.ReadBytes(SoundHeader.Length + 1 + wavFormatLen); //sound file offs _offs = reader.BaseStream.Position; if (parseNow) { _mp3Bytes = reader.ReadBytes(_soundDataLen); } else { reader.BaseStream.Position += _soundDataLen; } }
public byte[] GetBytes(bool pSaveInMemory = false) { if (mMp3bytes != null) { return(mMp3bytes); } if (mWzReader == null) { return(null); } long currentPos = mWzReader.BaseStream.Position; mWzReader.BaseStream.Position = mOffsets; int soundDataLen = mWzReader.ReadCompressedInt(); mWzReader.ReadCompressedInt(); //mWzReader.BaseStream.Position += 82; mMp3bytes = mWzReader.ReadBytes(soundDataLen); mWzReader.BaseStream.Position = currentPos; if (pSaveInMemory) { return(mMp3bytes); } byte[] result = mMp3bytes; mMp3bytes = null; return(result); }
/// <summary> /// Writes the WzImage object to the underlying WzBinaryWriter /// </summary> /// <param name="writer"></param> /// <param name="bIsWzUserKeyDefault">Uses the default MapleStory UserKey or a custom key.</param> /// <param name="forceReadFromData">Read from data regardless of base data that's changed or not.</param> public void SaveImage(WzBinaryWriter writer, bool bIsWzUserKeyDefault = true, bool forceReadFromData = false) { if (bIsImageChanged || !bIsWzUserKeyDefault || // everything needs to be re-written when a custom UserKey is used forceReadFromData) // if its not being force-read and written, it saves with the previous WZ encryption IV. { if (reader != null && !parsed) { this.ParseEverything = true; ParseImage(forceReadFromData); } WzSubProperty imgProp = new WzSubProperty(); long startPos = writer.BaseStream.Position; imgProp.AddPropertiesForWzImageDumping(WzProperties); imgProp.WriteValue(writer); writer.StringCache.Clear(); size = (int)(writer.BaseStream.Position - startPos); } else { long pos = reader.BaseStream.Position; reader.BaseStream.Position = offset; writer.Write(reader.ReadBytes(size)); reader.BaseStream.Position = pos; } }
public byte[] GetBytes(bool saveInMemory) { if (mp3bytes != null) { return(mp3bytes); } else { if (wzReader == null) { return(null); } long currentPos = wzReader.BaseStream.Position; wzReader.BaseStream.Position = offs; mp3bytes = wzReader.ReadBytes(soundDataLen); wzReader.BaseStream.Position = currentPos; if (saveInMemory) { return(mp3bytes); } else { byte[] result = mp3bytes; mp3bytes = null; return(result); } } }
/// <summary> /// Writes the WzImage object to the underlying WzBinaryWriter /// </summary> /// <param name="writer"></param> /// <param name="forceReadFromData">Read from data regardless of base data that's changed or not.</param> public void SaveImage(WzBinaryWriter writer, bool forceReadFromData = false) { if (changed || forceReadFromData) { if (reader != null && !parsed) { this.ParseEverything = true; ParseImage(forceReadFromData); } WzSubProperty imgProp = new WzSubProperty(); long startPos = writer.BaseStream.Position; imgProp.AddPropertiesForWzImageDumping(WzProperties); imgProp.WriteValue(writer); writer.StringCache.Clear(); size = (int)(writer.BaseStream.Position - startPos); } else { long pos = reader.BaseStream.Position; reader.BaseStream.Position = offset; writer.Write(reader.ReadBytes(size)); reader.BaseStream.Position = pos; } }
/// <summary> /// Creates a blank WzPngProperty /// </summary> /// <param name="reader"></param> /// <param name="parseNow"></param> internal WzPngProperty(WzBinaryReader reader, bool parseNow) { // Read compressed bytes width = reader.ReadCompressedInt(); height = reader.ReadCompressedInt(); format = reader.ReadCompressedInt(); format2 = reader.ReadByte(); reader.BaseStream.Position += 4; offs = reader.BaseStream.Position; int len = reader.ReadInt32() - 1; reader.BaseStream.Position += 1; if (len > 0) { if (parseNow) { if (wzReader == null) // when saving the WZ file to a new encryption { compressedImageBytes = reader.ReadBytes(len); } else // when opening the Wz property { compressedImageBytes = wzReader.ReadBytes(len); } ParsePng(); } else { reader.BaseStream.Position += len; } } this.wzReader = reader; }
internal void ParseSound(WzBinaryReader reader) { reader.BaseStream.Position++; int soundDataLen = reader.ReadCompressedInt(); reader.ReadCompressedInt(); mp3bytes = reader.ReadBytes(soundDataLen); }
/// <summary> /// BPS of the mp3 file /// </summary> //public byte BPS { get { return bps; } set { bps = value; } } /// <summary> /// Creates a WzSoundProperty with the specified name /// </summary> /// <param name="name">The name of the property</param> /// <param name="reader">The wz reader</param> /// <param name="parseNow">Indicating whether to parse the property now</param> public WzSoundProperty(string name, WzBinaryReader reader, bool parseNow) { this.name = name; wzReader = reader; reader.BaseStream.Position++; offs = reader.BaseStream.Position; //note - soundDataLen does NOT include the length of the header. int soundDataLen = reader.ReadCompressedInt(); len_ms = reader.ReadCompressedInt(); header = reader.ReadBytes(soundHeaderMask.Length); ParseHeader(); if (parseNow) { mp3bytes = reader.ReadBytes(soundDataLen); } else { reader.BaseStream.Position += soundDataLen; } }
public byte[] GetCompressedBytes(bool pSaveInMemory = false) { if (mCompressedBytes == null) { long pos = mWzReader.BaseStream.Position; mWzReader.BaseStream.Position = mOffsets; int len = mWzReader.ReadInt32() - 1; mWzReader.BaseStream.Position += 1; if (len > 0) { mCompressedBytes = mWzReader.ReadBytes(len); } mWzReader.BaseStream.Position = pos; if (!pSaveInMemory) { mCompressedBytes = null; return(mCompressedBytes); } } return(mCompressedBytes); }
public byte[] GetCompressedBytes(bool saveInMemory) { if (compressedBytes == null) { long pos = wzReader.BaseStream.Position; wzReader.BaseStream.Position = offs; int len = wzReader.ReadInt32() - 1; wzReader.BaseStream.Position += 1; if (len > 0) { compressedBytes = wzReader.ReadBytes(len); } wzReader.BaseStream.Position = pos; if (!saveInMemory) { //were removing the referance to compressedBytes, so a backup for the ret value is needed byte[] returnBytes = compressedBytes; compressedBytes = null; return(returnBytes); } } return(compressedBytes); }
/// <summary> /// Parses .lua property /// </summary> /// <param name="offset"></param> /// <param name="reader"></param> /// <param name="parent"></param> /// <param name="parentImg"></param> /// <returns></returns> internal static WzLuaProperty ParseLuaProperty(uint offset, WzBinaryReader reader, WzObject parent, WzImage parentImg) { // 28 71 4F EF 1B 65 F9 1F A7 48 8D 11 73 E7 F0 27 55 09 DD 3C 07 32 D7 38 21 57 84 70 C1 79 9A 3F 49 F7 79 03 41 F4 9D B9 1B 5F CF 26 80 3D EC 25 5F 9C // [compressed int] [bytes] int length = reader.ReadCompressedInt(); byte[] rawEncBytes = reader.ReadBytes(length); WzLuaProperty lua = new WzLuaProperty("Script", rawEncBytes) { Parent = parent }; return(lua); }
internal WzPngProperty(WzBinaryReader reader) { // Read compressed bytes width = reader.ReadCompressedInt(); height = reader.ReadCompressedInt(); format = reader.ReadCompressedInt(); format2 = reader.ReadByte(); reader.BaseStream.Position += 4; int len = reader.ReadInt32() - 1; reader.BaseStream.Position += 1; if (len > 0) { compressedBytes = reader.ReadBytes(len); } }
internal void ParseMainWzDirectory() { if (FilePath == null) { _log.Error("Path is null"); return; } if (!File.Exists(FilePath)) { var message = $"WZ File does not exist at path: '{FilePath}'"; _log.Error(message); throw new FileNotFoundException(message); } var reader = new WzBinaryReader(File.Open(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read), _wzIv); Header = new WzHeader { Ident = reader.ReadString(4), FSize = reader.ReadUInt64(), FStart = reader.ReadUInt32(), Copyright = reader.ReadNullTerminatedString() }; reader.ReadBytes((int)(Header.FStart - reader.BaseStream.Position)); reader.Header = Header; _version = reader.ReadInt16(); if (Version == -1 && !CalculateVersion(reader)) { throw new InvalidDataException( "Error with game version hash : The specified game version is incorrect"); } _versionHash = GetVersionHash(_version, Version); reader.Hash = _versionHash; var tempDirectory = new WzDirectory(reader, Name, _versionHash, _wzIv, this); tempDirectory.ParseDirectory(); WzDirectory = tempDirectory; }
private void ParseMainWzDirectory(byte[] wzIv) { if (FilePath == null) { throw new ArgumentNullException(nameof(FilePath), "WZ File path is null"); } if (!File.Exists(FilePath)) { throw new FileNotFoundException($"WZ File does not exist at path: '{FilePath}'"); } var mmf = MemoryMappedFile.CreateFromFile(FilePath); var reader = new WzBinaryReader(mmf.CreateViewStream(), wzIv); Header = new WzHeader { Ident = reader.ReadString(4), FSize = reader.ReadUInt64(), FStart = reader.ReadUInt32(), Copyright = reader.ReadNullTerminatedString() }; reader.ReadBytes((int)(Header.FStart - reader.BaseStream.Position)); reader.Header = Header; _version = reader.ReadInt16(); if (Version == -1 && !CalculateVersion(reader)) { throw new InvalidDataException( "Error with game version hash : The specified game version is incorrect"); } _versionHash = GetVersionHash(_version, Version); reader.Hash = _versionHash; var tempDirectory = new WzDirectory(reader, Name, _versionHash, wzIv, this); tempDirectory.ParseDirectory(); WzDirectory = tempDirectory; }
internal void SaveImage(WzBinaryWriter writer) { if (changed) { if (reader != null && !parsed) { ParseImage(); } WzSubProperty imgProp = new WzSubProperty(); long startPos = writer.BaseStream.Position; imgProp.AddProperties(WzProperties); imgProp.WriteValue(writer); writer.StringCache.Clear(); size = (int)(writer.BaseStream.Position - startPos); } else { long pos = reader.BaseStream.Position; reader.BaseStream.Position = offset; writer.Write(reader.ReadBytes(size)); reader.BaseStream.Position = pos; } }
internal WzPngProperty(WzBinaryReader reader, bool parseNow) { this.wzReader = reader; // Width Height width = reader.ReadCompressedInt(); height = reader.ReadCompressedInt(); if (this.width >= 0x10000 || this.height >= 0x10000) // copy pasta eric <3 { throw new ArgumentException(string.Format("Invalid WzPngProperty in Wz. Width: {0}, Height: {1}", width, height)); } // Image format nPixFormat = reader.ReadCompressedInt(); nMagLevel = reader.ReadByte(); // Other crap reader.BaseStream.Position += 4; offs = reader.BaseStream.Position; int len = reader.ReadInt32() - 1; reader.BaseStream.Position += 1; if (len > 0) { if (parseNow) { compressedBytes = wzReader.ReadBytes(len); ParsePng(); } else { reader.BaseStream.Position += len; } } wzReader = reader; }
private byte[] GetBytes(bool saveInMemory) { if (_mp3Bytes != null) { return(_mp3Bytes); } if (_wzReader == null) { return(null); } var currentPos = _wzReader.BaseStream.Position; _wzReader.BaseStream.Position = _offs; _mp3Bytes = _wzReader.ReadBytes(_soundDataLen); _wzReader.BaseStream.Position = currentPos; if (saveInMemory) { return(_mp3Bytes); } var result = _mp3Bytes; _mp3Bytes = null; return(result); }
internal void SaveImage(WzBinaryWriter writer) { if (Changed) { if (reader != null && !Parsed) { ParseImage(); } var imgProp = new WzSubProperty(); var startPos = writer.BaseStream.Position; imgProp.AddProperties(WzProperties); imgProp.WriteValue(writer); writer.StringCache.Clear(); BlockSize = (int)(writer.BaseStream.Position - startPos); } else { var pos = reader.BaseStream.Position; reader.BaseStream.Position = Offset; writer.Write(reader.ReadBytes(BlockSize)); reader.BaseStream.Position = pos; } }
/// <summary> /// Parse directories in the WZ file /// </summary> /// <param name="parseErrorMessage"></param> /// <param name="lazyParse">Only load the firt WzDirectory found if true</param> /// <returns></returns> internal bool ParseMainWzDirectory(out string parseErrorMessage, bool lazyParse = false) { if (this.path == null) { Helpers.ErrorLogger.Log(Helpers.ErrorLevel.Critical, "[Error] Path is null"); parseErrorMessage = "[Error] Path is null"; return(false); } WzBinaryReader reader = new WzBinaryReader(File.Open(this.path, FileMode.Open, FileAccess.Read, FileShare.Read), WzIv); this.Header = new WzHeader(); this.Header.Ident = reader.ReadString(4); this.Header.FSize = reader.ReadUInt64(); this.Header.FStart = reader.ReadUInt32(); this.Header.Copyright = reader.ReadNullTerminatedString(); reader.ReadBytes((int)(Header.FStart - reader.BaseStream.Position)); reader.Header = this.Header; this.version = reader.ReadInt16(); if (mapleStoryPatchVersion == -1) { const short MAX_PATCH_VERSION = 10000; // wont be reached for the forseeable future. for (int j = 0; j < MAX_PATCH_VERSION; j++) { this.mapleStoryPatchVersion = (short)j; this.versionHash = GetVersionHash(version, mapleStoryPatchVersion); if (this.versionHash == 0) { continue; } reader.Hash = this.versionHash; long position = reader.BaseStream.Position; // save position to rollback to, if should parsing fail from here WzDirectory testDirectory; try { testDirectory = new WzDirectory(reader, this.name, this.versionHash, this.WzIv, this); testDirectory.ParseDirectory(lazyParse); } catch { reader.BaseStream.Position = position; continue; } try { List <WzImage> childImages = testDirectory.GetChildImages(); if (childImages.Count == 0) // coincidentally in msea v194 Map001.wz, the hash matches exactly using mapleStoryPatchVersion of 113, and it fails to decrypt later on (probably 1 in a million chance). { reader.BaseStream.Position = position; // reset continue; } WzImage testImage = childImages[0]; try { reader.BaseStream.Position = testImage.Offset; byte checkByte = reader.ReadByte(); reader.BaseStream.Position = position; switch (checkByte) { case 0x73: case 0x1b: { WzDirectory directory = new WzDirectory(reader, this.name, this.versionHash, this.WzIv, this); directory.ParseDirectory(lazyParse); this.wzDir = directory; parseErrorMessage = "Success"; return(true); } default: { Helpers.ErrorLogger.Log(Helpers.ErrorLevel.MissingFeature, "New Wz image header found. checkByte = " + checkByte); // log or something break; } } reader.BaseStream.Position = position; // reset } catch { reader.BaseStream.Position = position; // reset } } finally { testDirectory.Dispose(); } } parseErrorMessage = "Error with game version hash : The specified game version is incorrect and WzLib was unable to determine the version itself"; } else { this.versionHash = GetVersionHash(version, mapleStoryPatchVersion); reader.Hash = this.versionHash; WzDirectory directory = new WzDirectory(reader, this.name, this.versionHash, this.WzIv, this); directory.ParseDirectory(); this.wzDir = directory; } parseErrorMessage = "Success"; return(true); }
internal void ParseMainWzDirectory(WzFile parentFile = null) { if (mPath == null) { Console.WriteLine("[Error] Path is null"); return; } byte[] key = WzKeyGenerator.GenerateWzKey(mWzIv); mReader = new WzBinaryReader(File.Open(mPath, FileMode.Open, FileAccess.Read, FileShare.Read), key, true); Header = new WzHeader { Ident = mReader.ReadString(4), FSize = mReader.ReadUInt64(), FStart = mReader.ReadUInt32(), Copyright = mReader.ReadNullTerminatedString() }; int bytesToRead = (int)(Header.FStart - mReader.BaseStream.Position); if (bytesToRead < 0) { throw new Exception("Unable to parse WZ file header"); } mReader.ReadBytes(bytesToRead); mReader.Header = Header; mVersion = mReader.ReadInt16(); if (mFileVersion == -1) { for (int j = 0; j < short.MaxValue; j++) { mFileVersion = (short)j; if (parentFile != null) { mFileVersion = parentFile.mFileVersion; } mVersionHash = GetVersionHash(mVersion, mFileVersion); if (mVersionHash == 0) { continue; } mReader.Hash = mVersionHash; long position = mReader.BaseStream.Position; WzDirectory testDirectory; try { testDirectory = new WzDirectory(mReader, mName, mVersionHash, mWzIv); testDirectory.ParseDirectory(); } catch { mReader.BaseStream.Position = position; continue; } foreach (WzImage s in testDirectory.GetChildImages()) { if (s.Name.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0) { testDirectory.Dispose(); throw new Exception("Invalid file names were detected. An invalid encryption may have been used."); } } WzImage testImage = testDirectory.GetChildImages()[0]; try { mReader.BaseStream.Position = testImage.Offset; byte checkByte = mReader.ReadByte(); mReader.BaseStream.Position = position; testDirectory.Dispose(); switch (checkByte) { case 0x73: case 0x1b: { mHash = mVersionHash; ParseDirectory(parentFile); return; } } mReader.BaseStream.Position = position; } catch { mReader.BaseStream.Position = position; } } throw new Exception("Error with game version hash : The specified game version is incorrect and WzLib was unable to determine the version itself"); } mVersionHash = GetVersionHash(mVersion, mFileVersion); mReader.Hash = mVersionHash; mHash = mVersionHash; ParseDirectory(parentFile); }
/// <summary> /// Parse directories in the WZ file /// </summary> /// <param name="parseErrorMessage"></param> /// <param name="lazyParse">Only load the firt WzDirectory found if true</param> /// <returns></returns> internal WzFileParseStatus ParseMainWzDirectory(bool lazyParse = false) { if (this.path == null) { Helpers.ErrorLogger.Log(Helpers.ErrorLevel.Critical, "[Error] Path is null"); return(WzFileParseStatus.Path_Is_Null); } WzBinaryReader reader = new WzBinaryReader(File.Open(this.path, FileMode.Open, FileAccess.Read, FileShare.Read), WzIv); this.Header = new WzHeader(); this.Header.Ident = reader.ReadString(4); this.Header.FSize = reader.ReadUInt64(); this.Header.FStart = reader.ReadUInt32(); this.Header.Copyright = reader.ReadString((int)(Header.FStart - 17U)); byte unk1 = reader.ReadByte(); byte[] unk2 = reader.ReadBytes((int)(Header.FStart - (ulong)reader.BaseStream.Position)); reader.Header = this.Header; this.wzVersionHeader = reader.ReadInt16(); if (mapleStoryPatchVersion == -1) { // Attempt to get version from MapleStory.exe first short maplestoryVerDetectedFromClient = GetMapleStoryVerFromExe(this.path, out this.mapleLocaleVersion); // this step is actually not needed if we know the maplestory patch version (the client .exe), but since we dont.. // we'll need a bruteforce way around it. const short MAX_PATCH_VERSION = 10000; // wont be reached for the forseeable future. for (int j = maplestoryVerDetectedFromClient; j < MAX_PATCH_VERSION; j++) { this.mapleStoryPatchVersion = (short)j; this.versionHash = CheckAndGetVersionHash(wzVersionHeader, mapleStoryPatchVersion); if (this.versionHash == 0) // ugly hack, but that's the only way if the version number isnt known (nexon stores this in the .exe) { continue; } reader.Hash = this.versionHash; long position = reader.BaseStream.Position; // save position to rollback to, if should parsing fail from here WzDirectory testDirectory; try { testDirectory = new WzDirectory(reader, this.name, this.versionHash, this.WzIv, this); testDirectory.ParseDirectory(lazyParse); } catch (Exception exp) { Debug.WriteLine(exp.ToString()); reader.BaseStream.Position = position; continue; } // test the image and see if its correct by parsing it bool bCloseTestDirectory = true; try { WzImage testImage = testDirectory.WzImages.FirstOrDefault(); if (testImage != null) { try { reader.BaseStream.Position = testImage.Offset; byte checkByte = reader.ReadByte(); reader.BaseStream.Position = position; switch (checkByte) { case 0x73: case 0x1b: { WzDirectory directory = new WzDirectory(reader, this.name, this.versionHash, this.WzIv, this); directory.ParseDirectory(lazyParse); this.wzDir = directory; return(WzFileParseStatus.Success); } case 0x30: case 0x6C: // idk case 0xBC: // Map002.wz? KMST? default: { Helpers.ErrorLogger.Log(Helpers.ErrorLevel.MissingFeature, string.Format("[WzFile.cs] New Wz image header found. checkByte = {0}. File Name = {1}", checkByte, Name)); // log or something break; } } reader.BaseStream.Position = position; // reset } catch { reader.BaseStream.Position = position; // reset } } else // if there's no image in the WZ file (new KMST Base.wz), test the directory instead { // coincidentally in msea v194 Map001.wz, the hash matches exactly using mapleStoryPatchVersion of 113, and it fails to decrypt later on (probably 1 in a million chance? o_O). // damn, technical debt accumulating here if (mapleStoryPatchVersion == 113) { // hack for now reader.BaseStream.Position = position; // reset continue; } else { this.wzDir = testDirectory; bCloseTestDirectory = false; return(WzFileParseStatus.Success); } } } finally { if (bCloseTestDirectory) { testDirectory.Dispose(); } } } //parseErrorMessage = "Error with game version hash : The specified game version is incorrect and WzLib was unable to determine the version itself"; return(WzFileParseStatus.Error_Game_Ver_Hash); } else { this.versionHash = CheckAndGetVersionHash(wzVersionHeader, mapleStoryPatchVersion); reader.Hash = this.versionHash; WzDirectory directory = new WzDirectory(reader, this.name, this.versionHash, this.WzIv, this); directory.ParseDirectory(); this.wzDir = directory; } return(WzFileParseStatus.Success); }
/// <summary> /// Parse directories in the WZ file /// </summary> /// <param name="parseErrorMessage"></param> /// <param name="lazyParse">Only load the firt WzDirectory found if true</param> /// <returns></returns> internal WzFileParseStatus ParseMainWzDirectory(bool lazyParse = false) { if (this.path == null) { Helpers.ErrorLogger.Log(Helpers.ErrorLevel.Critical, "[Error] Path is null"); return(WzFileParseStatus.Path_Is_Null); } WzBinaryReader reader = new WzBinaryReader(File.Open(this.path, FileMode.Open, FileAccess.Read, FileShare.Read), WzIv); this.Header = new WzHeader(); this.Header.Ident = reader.ReadString(4); this.Header.FSize = reader.ReadUInt64(); this.Header.FStart = reader.ReadUInt32(); this.Header.Copyright = reader.ReadString((int)(Header.FStart - 17U)); byte unk1 = reader.ReadByte(); byte[] unk2 = reader.ReadBytes((int)(Header.FStart - (ulong)reader.BaseStream.Position)); reader.Header = this.Header; Check64BitClient(reader); // update b64BitClient flag // 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(); 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) { for (ushort maplestoryVerToDecode = wzVersionHeader64bit_start; maplestoryVerToDecode < wzVersionHeader64bit_start + 10; maplestoryVerToDecode++) { if (TryDecodeWithWZVersionNumber(reader, wzVersionHeader, maplestoryVerToDecode, lazyParse)) { return(WzFileParseStatus.Success); } } } // Attempt to get version from MapleStory.exe first short maplestoryVerDetectedFromClient = GetMapleStoryVerFromExe(this.path, out this.mapleLocaleVersion); // this step is actually not needed if we know the maplestory patch version (the client .exe), but since we dont.. // we'll need a bruteforce way around it. const short MAX_PATCH_VERSION = 1000; // wont be reached for the forseeable future. for (int j = maplestoryVerDetectedFromClient; j < MAX_PATCH_VERSION; j++) { if (TryDecodeWithWZVersionNumber(reader, wzVersionHeader, j, lazyParse)) { return(WzFileParseStatus.Success); } } //parseErrorMessage = "Error with game version hash : The specified game version is incorrect and WzLib was unable to determine the version itself"; return(WzFileParseStatus.Error_Game_Ver_Hash); } else { this.versionHash = CheckAndGetVersionHash(wzVersionHeader, mapleStoryPatchVersion); reader.Hash = this.versionHash; WzDirectory directory = new WzDirectory(reader, this.name, this.versionHash, this.WzIv, this); directory.ParseDirectory(); this.wzDir = directory; } return(WzFileParseStatus.Success); }
internal void ParseMainWzDirectory() { if (FilePath == null) { Log.LogCritical("Path is null"); return; } var reader = new WzBinaryReader(File.Open(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read), _wzIv); Header = new WzHeader { Ident = reader.ReadString(4), FSize = reader.ReadUInt64(), FStart = reader.ReadUInt32(), Copyright = reader.ReadNullTerminatedString() }; reader.ReadBytes((int)(Header.FStart - reader.BaseStream.Position)); reader.Header = Header; _version = reader.ReadInt16(); if (FileVersion == -1) { for (var j = 0; j < short.MaxValue; j++) { FileVersion = (short)j; _versionHash = GetVersionHash(_version, FileVersion); if (_versionHash != 0) { reader.Hash = _versionHash; var position = reader.BaseStream.Position; WzDirectory testDirectory; try { testDirectory = new WzDirectory(reader, Name, _versionHash, _wzIv, this); testDirectory.ParseDirectory(); } catch { reader.BaseStream.Position = position; continue; } var testImage = testDirectory.GetChildImages()[0]; try { reader.BaseStream.Position = testImage.Offset; var checkByte = reader.ReadByte(); reader.BaseStream.Position = position; testDirectory.Dispose(); switch (checkByte) { case 0x73: case 0x1b: { var directory = new WzDirectory(reader, Name, _versionHash, _wzIv, this); directory.ParseDirectory(); WzDirectory = directory; return; } } reader.BaseStream.Position = position; } catch { reader.BaseStream.Position = position; } } } throw new Exception( "Error with game version hash : The specified game version is incorrect and WzLib was unable to determine the version itself"); } { _versionHash = GetVersionHash(_version, FileVersion); reader.Hash = _versionHash; var directory = new WzDirectory(reader, Name, _versionHash, _wzIv, this); directory.ParseDirectory(); WzDirectory = directory; } }
internal void ParseMainWzDirectory() { if (this.path == null) { Helpers.ErrorLogger.Log(Helpers.ErrorLevel.Critical, "[Error] Path is null"); return; } WzBinaryReader reader = new WzBinaryReader(File.Open(this.path, FileMode.Open, FileAccess.Read, FileShare.Read), mapleVersion); this.Header = new WzHeader(); this.Header.Ident = reader.ReadString(4); this.Header.FSize = reader.ReadUInt64(); this.Header.FStart = reader.ReadUInt32(); this.Header.Copyright = reader.ReadNullTerminatedString(); reader.ReadBytes((int)(Header.FStart - reader.BaseStream.Position)); reader.Header = this.Header; this.version = reader.ReadInt16(); if (fileVersion == -1) { for (int j = 0; j < short.MaxValue; j++) { this.fileVersion = (short)j; this.versionHash = GetVersionHash(version, fileVersion); if (this.versionHash != 0) { reader.Hash = this.versionHash; long position = reader.BaseStream.Position; WzDirectory testDirectory = null; try { testDirectory = new WzDirectory(reader, this.name, this.versionHash, this.WzIv, this); testDirectory.ParseDirectory(); } catch { reader.BaseStream.Position = position; continue; } WzImage testImage = testDirectory.GetChildImages()[0]; try { reader.BaseStream.Position = testImage.Offset; byte checkByte = reader.ReadByte(); reader.BaseStream.Position = position; testDirectory.Dispose(); switch (checkByte) { case 0x73: case 0x1b: { WzDirectory directory = new WzDirectory(reader, this.name, this.versionHash, this.WzIv, this); directory.ParseDirectory(); this.wzDir = directory; return; } } reader.BaseStream.Position = position; } catch { reader.BaseStream.Position = position; } } } throw new Exception("Error with game version hash : The specified game version is incorrect and WzLib was unable to determine the version itself"); } else { this.versionHash = GetVersionHash(version, fileVersion); reader.Hash = this.versionHash; WzDirectory directory = new WzDirectory(reader, this.name, this.versionHash, this.WzIv, this); directory.ParseDirectory(); this.wzDir = directory; } }
/// <summary> /// Parse directories in the WZ file /// </summary> /// <param name="parseErrorMessage"></param> /// <param name="lazyParse">Only load the firt WzDirectory found if true</param> /// <returns></returns> internal WzFileParseStatus ParseMainWzDirectory(bool lazyParse = false) { if (this.path == null) { Helpers.ErrorLogger.Log(Helpers.ErrorLevel.Critical, "[Error] Path is null"); return(WzFileParseStatus.Path_Is_Null); } WzBinaryReader reader = new WzBinaryReader(File.Open(this.path, FileMode.Open, FileAccess.Read, FileShare.Read), WzIv); this.Header = new WzHeader(); this.Header.Ident = reader.ReadString(4); this.Header.FSize = reader.ReadUInt64(); this.Header.FStart = reader.ReadUInt32(); this.Header.Copyright = reader.ReadString((int)(Header.FStart - 17U)); reader.ReadBytes(1); reader.ReadBytes((int)(Header.FStart - (ulong)reader.BaseStream.Position)); reader.Header = this.Header; this.version = reader.ReadInt16(); if (mapleStoryPatchVersion == -1) { const short MAX_PATCH_VERSION = 10000; // wont be reached for the forseeable future. for (int j = 0; j < MAX_PATCH_VERSION; j++) { this.mapleStoryPatchVersion = (short)j; this.versionHash = CheckAndGetVersionHash(version, mapleStoryPatchVersion); if (this.versionHash == 0) // ugly hack, but that's the only way if the version number isnt known (nexon stores this in the .exe) { continue; } reader.Hash = this.versionHash; long position = reader.BaseStream.Position; // save position to rollback to, if should parsing fail from here WzDirectory testDirectory; try { testDirectory = new WzDirectory(reader, this.name, this.versionHash, this.WzIv, this); testDirectory.ParseDirectory(lazyParse); } catch (Exception exp) { Debug.WriteLine(exp.ToString()); reader.BaseStream.Position = position; continue; } try { List <WzImage> childImages = testDirectory.GetChildImages(); if (childImages.Count == 0) // coincidentally in msea v194 Map001.wz, the hash matches exactly using mapleStoryPatchVersion of 113, and it fails to decrypt later on (probably 1 in a million chance). { reader.BaseStream.Position = position; // reset continue; } WzImage testImage = childImages[0]; try { reader.BaseStream.Position = testImage.Offset; byte checkByte = reader.ReadByte(); reader.BaseStream.Position = position; switch (checkByte) { case 0x73: case 0x1b: { WzDirectory directory = new WzDirectory(reader, this.name, this.versionHash, this.WzIv, this); directory.ParseDirectory(lazyParse); this.wzDir = directory; return(WzFileParseStatus.Success); } case 0x30: case 0x6C: // idk case 0xBC: // Map002.wz? KMST? default: { Helpers.ErrorLogger.Log(Helpers.ErrorLevel.MissingFeature, string.Format("[WzFile.cs] New Wz image header found. checkByte = {0}. File Name = {1}", checkByte, Name)); // log or something break; } } reader.BaseStream.Position = position; // reset } catch { reader.BaseStream.Position = position; // reset } } finally { testDirectory.Dispose(); } } //parseErrorMessage = "Error with game version hash : The specified game version is incorrect and WzLib was unable to determine the version itself"; return(WzFileParseStatus.Error_Game_Ver_Hash); } else { this.versionHash = CheckAndGetVersionHash(version, mapleStoryPatchVersion); reader.Hash = this.versionHash; WzDirectory directory = new WzDirectory(reader, this.name, this.versionHash, this.WzIv, this); directory.ParseDirectory(); this.wzDir = directory; } return(WzFileParseStatus.Success); }