Example #1
0
        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;
            }
        }
Example #4
0
        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);
        }
Example #5
0
        /// <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;
        }
Example #9
0
        internal void ParseSound(WzBinaryReader reader)
        {
            reader.BaseStream.Position++;
            int soundDataLen = reader.ReadCompressedInt();

            reader.ReadCompressedInt();
            mp3bytes = reader.ReadBytes(soundDataLen);
        }
Example #10
0
        /// <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;
            }
        }
Example #11
0
 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);
 }
Example #13
0
        /// <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);
        }
Example #14
0
        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);
            }
        }
Example #15
0
        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;
        }
Example #16
0
        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;
        }
Example #17
0
 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);
        }
Example #20
0
        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);
        }
Example #22
0
        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);
        }
Example #23
0
        /// <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);
        }
Example #25
0
        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;
            }
        }
Example #26
0
        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;
            }
        }
Example #27
0
        /// <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);
        }