public WzImage(string name, Stream dataStream, WzMapleVersion mapleVersion) { this.name = name; this.reader = new WzBinaryReader(dataStream, WzTool.GetIvByMapleVersion(mapleVersion)); }
/// <summary> /// Parses the extended property /// </summary> /// <param name="reader">The current BinaryReader that's reading the wz file</param> internal void ParseExtendedProperty(WzBinaryReader reader) { this.reader = reader; DumpBlock(endOfBlock, name); }
internal static IExtended ExtractMore(WzBinaryReader reader, uint offset, int eob, string name, string iname, IWzObject parent, WzImage imgParent) { if (iname == "") { iname = reader.ReadString(); } switch (iname) { case "Property": WzSubProperty subProp = new WzSubProperty(name) { Parent = parent }; reader.BaseStream.Position += 2; subProp.AddProperties(IWzImageProperty.ParsePropertyList(offset, reader, subProp, imgParent)); return(subProp); case "Canvas": WzCanvasProperty canvasProp = new WzCanvasProperty(name) { Parent = parent }; reader.BaseStream.Position++; if (reader.ReadByte() == 1) { reader.BaseStream.Position += 2; canvasProp.AddProperties(IWzImageProperty.ParsePropertyList(offset, reader, canvasProp, imgParent)); } canvasProp.PngProperty = new WzPngProperty(reader, imgParent.parseEverything) { Parent = canvasProp }; return(canvasProp); case "Shape2D#Vector2D": WzVectorProperty vecProp = new WzVectorProperty(name) { Parent = parent }; vecProp.X = new WzCompressedIntProperty("X", reader.ReadCompressedInt()) { Parent = vecProp }; vecProp.Y = new WzCompressedIntProperty("Y", reader.ReadCompressedInt()) { Parent = vecProp }; return(vecProp); case "Shape2D#Convex2D": WzConvexProperty convexProp = new WzConvexProperty(name) { Parent = parent }; int convexEntryCount = reader.ReadCompressedInt(); convexProp.WzProperties.Capacity = convexEntryCount; //performance thing for (int i = 0; i < convexEntryCount; i++) { convexProp.AddProperty(ParseExtendedProp(reader, offset, 0, name, convexProp, imgParent)); } return(convexProp); case "Sound_DX8": WzSoundProperty soundProp = new WzSoundProperty(name, reader, imgParent.parseEverything) { Parent = parent }; return(soundProp); case "UOL": reader.BaseStream.Position++; switch (reader.ReadByte()) { case 0: return(new WzUOLProperty(name, reader.ReadString()) { Parent = parent }); case 1: return(new WzUOLProperty(name, reader.ReadStringAtOffset(offset + reader.ReadInt32())) { Parent = parent }); } throw new Exception("Unsupported UOL type"); default: throw new Exception("Unknown iname: " + iname); } }
/// <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); }
internal static List <AWzImageProperty> ParsePropertyList(uint pOffset, WzBinaryReader pReader, AWzObject pParent, WzImage pParentImg) { List <AWzImageProperty> properties = new List <AWzImageProperty>(); int entryCount = pReader.ReadCompressedInt(); for (int i = 0; i < entryCount; i++) { string name = pReader.ReadStringBlock(pOffset).Trim(); byte b = pReader.ReadByte(); switch (b) { case 0: properties.Add(new WzNullProperty(name) { Parent = pParent, ParentImage = pParentImg }); break; case 2: case 11: //UShort properties.Add(new WzShortProperty(name, pReader.ReadInt16()) { Parent = pParent, ParentImage = pParentImg }); break; case 3: case 19: //UInt properties.Add(new WzCompressedIntProperty(name, pReader.ReadCompressedInt()) { Parent = pParent, ParentImage = pParentImg }); break; case 4: byte type = pReader.ReadByte(); if (type == 0x80) { properties.Add(new WzByteFloatProperty(name, pReader.ReadSingle()) { Parent = pParent, ParentImage = pParentImg }); } else if (type == 0) { properties.Add(new WzByteFloatProperty(name, 0f) { Parent = pParent, ParentImage = pParentImg }); } break; case 5: properties.Add(new WzDoubleProperty(name, pReader.ReadDouble()) { Parent = pParent, ParentImage = pParentImg }); break; case 8: properties.Add(new WzStringProperty(name, pReader.ReadStringBlock(pOffset)) { Parent = pParent, ParentImage = pParentImg }); break; case 9: int eob = (int)(pReader.ReadUInt32() + pReader.BaseStream.Position); AWzImageProperty exProp = ParseExtendedProp(pReader, pOffset, eob, name, pParent, pParentImg); if (exProp != null) { properties.Add(exProp); } pReader.BaseStream.Position = eob; break; case 20: properties.Add(new WzCompressedLongProperty(name, pReader.ReadCompressedLong()) { Parent = pParent, ParentImage = pParentImg }); break; default: throw new Exception("Unknown property type at ParsePropertyList: " + b + " name: " + name + " offset: " + pReader.getCurrentOffset()); } } return(properties); }
internal static List <IWzImageProperty> ParsePropertyList(uint offset, WzBinaryReader reader, IWzObject parent, WzImage parentImg) { int entryCount = reader.ReadCompressedInt(); List <IWzImageProperty> properties = new List <IWzImageProperty>(entryCount); for (int i = 0; i < entryCount; i++) { string name = reader.ReadStringBlock(offset); switch (reader.ReadByte()) { case 0: properties.Add(new WzNullProperty(name) { Parent = parent /*, ParentImage = parentImg*/ }); break; case 0x0B: case 2: properties.Add(new WzUnsignedShortProperty(name, reader.ReadUInt16()) { Parent = parent /*, ParentImage = parentImg*/ }); break; case 3: properties.Add(new WzCompressedIntProperty(name, reader.ReadCompressedInt()) { Parent = parent /*, ParentImage = parentImg*/ }); break; case 4: byte type = reader.ReadByte(); if (type == 0x80) { properties.Add(new WzByteFloatProperty(name, reader.ReadSingle()) { Parent = parent /*, ParentImage = parentImg*/ }); } else if (type == 0) { properties.Add(new WzByteFloatProperty(name, 0f) { Parent = parent /*, ParentImage = parentImg*/ }); } break; case 5: properties.Add(new WzDoubleProperty(name, reader.ReadDouble()) { Parent = parent /*, ParentImage = parentImg*/ }); break; case 8: properties.Add(new WzStringProperty(name, reader.ReadStringBlock(offset)) { Parent = parent }); break; case 9: int eob = (int)(reader.ReadUInt32() + reader.BaseStream.Position); IWzImageProperty exProp = ParseExtendedProp(reader, offset, eob, name, parent, parentImg); properties.Add(exProp); if (reader.BaseStream.Position != eob) { reader.BaseStream.Position = eob; } break; default: throw new Exception("Unknown property type at ParsePropertyList"); } } return(properties); }
/// <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 WzImage(string name, WzBinaryReader reader) { this.name = name; this.reader = reader; this.blockStart = (int)reader.BaseStream.Position; }
/// <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); }
private bool TryDecodeWithWZVersionNumber(WzBinaryReader reader, int useWzVersionHeader, int useMapleStoryPatchVersion, bool lazyParse) { this.mapleStoryPatchVersion = (short)useMapleStoryPatchVersion; this.versionHash = CheckAndGetVersionHash(useWzVersionHeader, 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) { return(false); } reader.Hash = this.versionHash; long fallbackOffsetPosition = 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 = fallbackOffsetPosition; return(false); } // 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 = fallbackOffsetPosition; 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(true); } 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 = fallbackOffsetPosition; // reset } catch { reader.BaseStream.Position = fallbackOffsetPosition; // reset return(false); } return(true); } 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 = fallbackOffsetPosition; // reset return(false); } else { this.wzDir = testDirectory; bCloseTestDirectory = false; return(true); } } } finally { if (bCloseTestDirectory) { testDirectory.Dispose(); } } }
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 WzImage(string name, WzBinaryReader reader) { Name = name; Reader = reader; BlockStart = (int)reader.BaseStream.Position; }
internal static AWzImageProperty ExtractMore(WzBinaryReader pReader, uint pOffset, int pEndOfBlock, string pName, string pImageName, AWzObject pParent, WzImage pImgParent) { switch (pImageName) { case "Property": WzSubProperty subProp = new WzSubProperty(pName) { Parent = pParent, ParentImage = pImgParent }; pReader.BaseStream.Position += 2; subProp.AddProperties(ParsePropertyList(pOffset, pReader, subProp, pImgParent)); return(subProp); case "Canvas": WzCanvasProperty canvasProp = new WzCanvasProperty(pName) { Parent = pParent, ParentImage = pImgParent }; pReader.BaseStream.Position++; if (pReader.ReadByte() == 1) { pReader.BaseStream.Position += 2; canvasProp.AddProperties(ParsePropertyList(pOffset, pReader, canvasProp, pImgParent)); } canvasProp.PngProperty = new WzPngProperty(pReader) { Parent = canvasProp, ParentImage = pImgParent }; return(canvasProp); case "Shape2D#Vector2D": WzVectorProperty vecProp = new WzVectorProperty(pName) { Parent = pParent, ParentImage = pImgParent }; vecProp.X = new WzCompressedIntProperty("X", pReader.ReadCompressedInt()) { Parent = vecProp, ParentImage = pImgParent }; vecProp.Y = new WzCompressedIntProperty("Y", pReader.ReadCompressedInt()) { Parent = vecProp, ParentImage = pImgParent }; return(vecProp); case "Shape2D#Convex2D": WzConvexProperty convexProp = new WzConvexProperty(pName) { Parent = pParent, ParentImage = pImgParent }; int convexEntryCount = pReader.ReadCompressedInt(); for (int i = 0; i < convexEntryCount; i++) { AWzImageProperty imgProp = ParseExtendedProp(pReader, pOffset, 0, pName, convexProp, pImgParent); if (imgProp != null) { convexProp.AddProperty(imgProp); } } return(convexProp); case "Sound_DX8": WzSoundProperty soundProp = new WzSoundProperty(pName) { Parent = pParent, ParentImage = pImgParent }; soundProp.ParseSound(pReader); return(soundProp); case "UOL": pReader.BaseStream.Position++; byte b = pReader.ReadByte(); switch (b) { case 0: return(new WzUOLProperty(pName, pReader.ReadString()) { Parent = pParent, ParentImage = pImgParent }); case 1: return(new WzUOLProperty(pName, pReader.ReadStringAtOffset(pOffset + pReader.ReadInt32())) { Parent = pParent, ParentImage = pImgParent }); default: throw new Exception("Unsupported UOL type: " + b); } default: throw new Exception("Unknown image name: " + pImageName); } }
/// <summary> /// Dispose the object /// </summary> public override void Dispose() { name = null; extendedProperty.Dispose(); reader = null; }
/// <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); }
public WzImage(string name, Stream dataStream, WzMapleVersion mapleVersion) { this.name = name; this.reader = new WzBinaryReader(dataStream, mapleVersion.EncryptionKey()); }
internal WzImage(string name, WzBinaryReader reader) { Name = name; Reader = reader; }
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), 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 (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; } }
public WzImage(string pName, Stream pDataStream, WzMapleVersion pMapleVersion) { mName = pName; mReader = new WzBinaryReader(pDataStream, WzTool.GetIvByMapleVersion(pMapleVersion)); initialParse = true; }