Exemple #1
0
        /// <summary>
        /// Parses a wz list file on the disk
        /// </summary>
        /// <param name="filePath">Path to the wz file</param>
        /// <param name="wzIv"></param>
        public static List <string> ParseListFile(string filePath, byte[] wzIv)
        {
            var listEntries = new List <string>();
            var wzFileBytes = File.ReadAllBytes(filePath);
            var wzParser    = new WzBinaryReader(new MemoryStream(wzFileBytes), wzIv);

            while (wzParser.PeekChar() != -1)
            {
                var len     = wzParser.ReadInt32();
                var strChrs = new char[len];
                for (var i = 0; i < len; i++)
                {
                    strChrs[i] = (char)wzParser.ReadInt16();
                }

                wzParser.ReadUInt16(); //encrypted null
                var decryptedStr = wzParser.DecryptString(strChrs);
                listEntries.Add(decryptedStr);
            }

            wzParser.Close();
            var lastIndex = listEntries.Count - 1;
            var lastEntry = listEntries[lastIndex];

            listEntries[lastIndex] = lastEntry.Substring(0, lastEntry.Length - 1) + "g";
            return(listEntries);
        }
Exemple #2
0
        /// <summary>
        /// Parses the wz list file
        /// </summary>
        public void ParseWzFile()
        {
            //WzTools.CreateWzKey(WzMapleVersion.GMS);//what?
            WzBinaryReader wzParser = new WzBinaryReader(new MemoryStream(wzFileBytes), WzIv);

            while (wzParser.PeekChar() != -1)
            {
                int    Len  = wzParser.ReadInt32();
                char[] List = new char[Len];
                for (int i = 0; i < Len; i++)
                {
                    List[i] = (char)wzParser.ReadInt16();
                }
                wzParser.ReadUInt16();
                string Decrypted = wzParser.DecryptString(List);
                if (wzParser.PeekChar() == -1)
                {
                    if (Decrypted[Decrypted.Length - 1] == '/')
                    {
                        Decrypted = Decrypted.TrimEnd("/".ToCharArray()) + "g";                         // Last char should always be a g (.img)
                    }
                }
                listEntries.Add(Decrypted);
            }
            wzParser.Close();
        }
Exemple #3
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;
        }
Exemple #4
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;
        }
Exemple #5
0
 /// <summary>
 /// Parses the wz list file
 /// </summary>
 public void ParseWzFile()
 {
     using (WzBinaryReader wzParser = new WzBinaryReader(new MemoryStream(mWzFileBytes), mWzIv)) {
         while (wzParser.PeekChar() != -1)
         {
             int    Len  = wzParser.ReadInt32();
             char[] List = new char[Len];
             for (int i = 0; i < Len; i++)
             {
                 List[i] = (char)wzParser.ReadInt16();
             }
             wzParser.ReadUInt16();
             string Decrypted = wzParser.DecryptString(List);
             if (wzParser.PeekChar() == -1)
             {
                 if (Decrypted[Decrypted.Length - 1] == '/')
                 {
                     Decrypted = Decrypted.TrimEnd("/".ToCharArray()) + "g"; // Last char should always be a g (.img)
                 }
             }
             mListEntries.Add(Decrypted);
         }
     }
 }
        /// <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);
        }
Exemple #7
0
        /// <summary>
        /// Parses the WzDirectory
        /// </summary>
        internal void ParseDirectory()
        {
            int entryCount = reader.ReadCompressedInt();

            for (int i = 0; i < entryCount; i++)
            {
                byte   type  = reader.ReadByte();
                string fname = null;
                int    fsize;
                int    checksum;
                uint   offset;

                long rememberPos = 0;
                if (type == 1) //01 XX 00 00 00 00 00 OFFSET (4 bytes)
                {
                    int unknown = reader.ReadInt32();
                    reader.ReadInt16();
                    uint offs = reader.ReadOffset();
                    continue;
                }
                else if (type == 2)
                {
                    int stringOffset = reader.ReadInt32();
                    rememberPos = reader.BaseStream.Position;
                    reader.BaseStream.Position = reader.Header.FStart + stringOffset;
                    type  = reader.ReadByte();
                    fname = reader.ReadString();
                }
                else if (type == 3 || type == 4)
                {
                    fname       = reader.ReadString();
                    rememberPos = reader.BaseStream.Position;
                }
                else
                {
                }
                reader.BaseStream.Position = rememberPos;
                fsize    = reader.ReadCompressedInt();
                checksum = reader.ReadCompressedInt();
                offset   = reader.ReadOffset();
                if (type == 3)
                {
                    WzDirectory subDir = new WzDirectory(reader, fname, hash, WzIv, wzFile);
                    subDir.BlockSize = fsize;
                    subDir.Checksum  = checksum;
                    subDir.Offset    = offset;
                    subDir.Parent    = this;
                    subDirs.Add(subDir);
                }
                else
                {
                    WzImage img = new WzImage(fname, reader);
                    img.BlockSize = fsize;
                    img.Checksum  = checksum;
                    img.Offset    = offset;
                    img.Parent    = this;
                    images.Add(img);
                }
            }

            foreach (WzDirectory subdir in subDirs)
            {
                reader.BaseStream.Position = subdir.offset;
                subdir.ParseDirectory();
            }
        }
Exemple #8
0
        internal static List <WzImageProperty> ParsePropertyList(uint offset, WzBinaryReader reader, WzObject parent, WzImage parentImg)
        {
            int entryCount = reader.ReadCompressedInt();
            List <WzImageProperty> properties = new List <WzImageProperty>(entryCount);

            for (int i = 0; i < entryCount; i++)
            {
                string name  = reader.ReadStringBlock(offset);
                byte   ptype = reader.ReadByte();
                switch (ptype)
                {
                case 0:
                    properties.Add(new WzNullProperty(name)
                    {
                        Parent = parent
                    });
                    break;

                case 11:
                case 2:
                    properties.Add(new WzShortProperty(name, reader.ReadInt16())
                    {
                        Parent = parent
                    });
                    break;

                case 3:
                case 19:
                    properties.Add(new WzIntProperty(name, reader.ReadCompressedInt())
                    {
                        Parent = parent
                    });
                    break;

                case 20:
                    properties.Add(new WzLongProperty(name, reader.ReadLong())
                    {
                        Parent = parent
                    });
                    break;

                case 4:
                    byte type = reader.ReadByte();
                    if (type == 0x80)
                    {
                        properties.Add(new WzFloatProperty(name, reader.ReadSingle())
                        {
                            Parent = parent
                        });
                    }
                    else if (type == 0)
                    {
                        properties.Add(new WzFloatProperty(name, 0f)
                        {
                            Parent = parent
                        });
                    }
                    break;

                case 5:
                    properties.Add(new WzDoubleProperty(name, reader.ReadDouble())
                    {
                        Parent = parent
                    });
                    break;

                case 8:
                    properties.Add(new WzStringProperty(name, reader.ReadStringBlock(offset))
                    {
                        Parent = parent
                    });
                    break;

                case 9:
                    int             eob    = (int)(reader.ReadUInt32() + reader.BaseStream.Position);
                    WzImageProperty 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);
        }
Exemple #9
0
        /// <summary>
        /// Parses the WzDirectory
        /// <paramref name="lazyParse">Only parses the first directory</paramref>
        /// </summary>
        internal void ParseDirectory(bool lazyParse = false)
        {
            //Debug.WriteLine(HexTool.ToString( reader.ReadBytes(20)));
            //reader.BaseStream.Position = reader.BaseStream.Position - 20;

            int entryCount = reader.ReadCompressedInt();

            for (int i = 0; i < entryCount; i++)
            {
                byte   type  = reader.ReadByte();
                string fname = null;
                int    fsize;
                int    checksum;
                uint   offset;

                long rememberPos = 0;
                switch (type)
                {
                case 1:      //01 XX 00 00 00 00 00 OFFSET (4 bytes)
                {
                    int unknown = reader.ReadInt32();
                    reader.ReadInt16();
                    uint offs = reader.ReadOffset();
                    continue;
                }

                case 2:
                {
                    int stringOffset = reader.ReadInt32();
                    rememberPos = reader.BaseStream.Position;
                    reader.BaseStream.Position = reader.Header.FStart + stringOffset;
                    type  = reader.ReadByte();
                    fname = reader.ReadString();
                    break;
                }

                case 3:
                case 4:
                {
                    fname       = reader.ReadString();
                    rememberPos = reader.BaseStream.Position;
                    break;
                }

                default:
                {
                    break;
                }
                }
                reader.BaseStream.Position = rememberPos;
                fsize    = reader.ReadCompressedInt();
                checksum = reader.ReadCompressedInt();
                offset   = reader.ReadOffset();
                if (type == 3)
                {
                    WzDirectory subDir = new WzDirectory(reader, fname, hash, WzIv, wzFile);
                    subDir.BlockSize = fsize;
                    subDir.Checksum  = checksum;
                    subDir.Offset    = offset;
                    subDir.Parent    = this;
                    subDirs.Add(subDir);

                    if (lazyParse)
                    {
                        break;
                    }
                }
                else
                {
                    WzImage img = new WzImage(fname, reader);
                    img.BlockSize = fsize;
                    img.Checksum  = checksum;
                    img.Offset    = offset;
                    img.Parent    = this;
                    images.Add(img);

                    if (lazyParse)
                    {
                        break;
                    }
                }
            }

            foreach (WzDirectory subdir in subDirs)
            {
                reader.BaseStream.Position = subdir.offset;
                subdir.ParseDirectory();
            }
        }
Exemple #10
0
        /// <summary>
        /// Parses the WzDirectory
        /// </summary>
        internal void ParseDirectory(WzFile parent = null)
        {
            //Array.Copy(mReader.WzKey, keyCopy, mReader.WzKey.Length);
            int entryCount = mReader.ReadCompressedInt();

            for (int i = 0; i < entryCount; i++)
            {
                byte   type  = mReader.ReadByte();
                string fname = null;
                int    fsize;
                int    checksum;
                uint   offset;
                long   rememberPos = 0;
                switch (type)
                {
                case 1: {
                    mReader.ReadInt32();
                    mReader.ReadInt16();
                    mReader.ReadOffset();
                    continue;
                }

                case 2: {
                    int stringOffset = mReader.ReadInt32();
                    rememberPos = mReader.BaseStream.Position;
                    mReader.BaseStream.Position = mReader.Header.FStart + stringOffset;
                    type  = mReader.ReadByte();
                    fname = mReader.ReadString().Trim();
                }
                break;

                case 3:
                case 4:
                    fname       = mReader.ReadString().Trim();
                    rememberPos = mReader.BaseStream.Position;
                    break;
                }
                mReader.BaseStream.Position = rememberPos;
                fsize    = mReader.ReadCompressedInt();
                checksum = mReader.ReadCompressedInt();
                offset   = mReader.ReadOffset();
                if (type == 3)
                {
                    WzDirectory subDir = new WzDirectory(mReader, fname, mHash, mWzIv)
                    {
                        BlockSize = fsize, Checksum = checksum, Offset = offset, Parent = parent ?? this
                    };
                    if (parent != null)
                    {
                        parent.mSubDirs.Add(subDir);
                    }
                    mSubDirs.Add(subDir);
                }
                else
                {
                    WzImage img = new WzImage(fname, mReader)
                    {
                        BlockSize = fsize, Checksum = checksum, Offset = offset, Parent = parent ?? this
                    };
                    if (parent != null)
                    {
                        parent.mImages.Add(img);
                    }
                    mImages.Add(img);
                }
            }
            foreach (WzDirectory subdir in mSubDirs)
            {
                mReader.BaseStream.Position = subdir.mOffset;
                subdir.ParseDirectory();
            }
        }
        /// <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);
        }
        /// <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);
        }
Exemple #13
0
        /// <summary>
        /// Parses the WzDirectory
        /// <paramref name="lazyParse">Only parses the first directory</paramref>
        /// </summary>
        internal void ParseDirectory(bool lazyParse = false)
        {
            //Debug.WriteLine(HexTool.ToString( reader.ReadBytes(20)));
            //reader.BaseStream.Position = reader.BaseStream.Position - 20;
            long available = reader.Available();

            if (available == 0)
            {
                return;
            }

            int entryCount = reader.ReadCompressedInt();

            if (entryCount < 0 || entryCount > 100000) // probably nothing > 100k folders for now.
            {
                throw new Exception("Invalid wz version used for decryption, try parsing other version numbers.");
            }

            for (int i = 0; i < entryCount; i++)
            {
                byte   type  = reader.ReadByte();
                string fname = null;
                int    fsize;
                int    checksum;
                uint   offset;

                long rememberPos = 0;
                switch (type)
                {
                case 1:      //01 XX 00 00 00 00 00 OFFSET (4 bytes)
                {
                    int unknown = reader.ReadInt32();
                    reader.ReadInt16();
                    uint offs = reader.ReadOffset();
                    continue;
                }

                case 2:
                {
                    int stringOffset = reader.ReadInt32();
                    rememberPos = reader.BaseStream.Position;
                    reader.BaseStream.Position = reader.Header.FStart + stringOffset;
                    type  = reader.ReadByte();
                    fname = reader.ReadString();
                    break;
                }

                case 3:
                case 4:
                {
                    fname       = reader.ReadString();
                    rememberPos = reader.BaseStream.Position;
                    break;
                }

                default:
                {
                    throw new Exception("[WzDirectory] Unknown directory. type = " + type);
                }
                }
                reader.BaseStream.Position = rememberPos;
                fsize    = reader.ReadCompressedInt();
                checksum = reader.ReadCompressedInt();
                offset   = reader.ReadOffset(); // IWzArchive::Getposition(pArchive)

                if (type == 3)
                {
                    WzDirectory subDir = new WzDirectory(reader, fname, hash, WzIv, wzFile)
                    {
                        BlockSize = fsize,
                        Checksum  = checksum,
                        Offset    = offset,
                        Parent    = this
                    };
                    subDirs.Add(subDir);

                    if (lazyParse)
                    {
                        break;
                    }
                }
                else
                {
                    WzImage img = new WzImage(fname, reader, checksum)
                    {
                        BlockSize = fsize,
                        Offset    = offset,
                        Parent    = this
                    };
                    images.Add(img);

                    if (lazyParse)
                    {
                        break;
                    }
                }
            }

            foreach (WzDirectory subdir in subDirs)
            {
                if (subdir.Checksum != 0)
                {
                    reader.BaseStream.Position = subdir.offset;
                    subdir.ParseDirectory();
                }
            }
        }
Exemple #14
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;
            }
        }
Exemple #15
0
        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);
        }
Exemple #16
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;
            }
        }
Exemple #17
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);
        }
Exemple #18
0
        /// <summary>
        /// Parses the WzDirectory
        /// </summary>
        internal void ParseDirectory()
        {
            var entryCount = _reader.ReadCompressedInt();

            for (var i = 0; i < entryCount; i++)
            {
                var    type  = _reader.ReadByte();
                string fname = null;

                long rememberPos = 0;

                switch (type)
                {
                case 1:
                    var unknown = _reader.ReadInt32();
                    _reader.ReadInt16();
                    var offs = _reader.ReadOffset();
                    continue;

                case 2:
                    var stringOffset = _reader.ReadInt32();
                    rememberPos = _reader.BaseStream.Position;
                    _reader.BaseStream.Position = _reader.Header.FStart + stringOffset;
                    type  = _reader.ReadByte();
                    fname = _reader.ReadString();
                    break;

                case 3:
                case 4:
                    fname       = _reader.ReadString();
                    rememberPos = _reader.BaseStream.Position;
                    break;
                }

                _reader.BaseStream.Position = rememberPos;
                var fsize       = _reader.ReadCompressedInt();
                var dirChecksum = _reader.ReadCompressedInt();
                var dirOffset   = _reader.ReadOffset();
                if (type == 3)
                {
                    var subDir = new WzDirectory(_reader, fname, _hash, WzIv, _wzFile)
                    {
                        BlockSize = fsize,
                        Checksum  = dirChecksum,
                        Offset    = dirOffset,
                        Parent    = this
                    };
                    WzDirectories.Add(subDir);
                }
                else
                {
                    var img = new WzImage(fname, _reader)
                    {
                        BlockSize = fsize,
                        Checksum  = dirChecksum,
                        Offset    = dirOffset,
                        Parent    = this
                    };
                    WzImages.Add(img);
                }
            }

            foreach (var subdir in WzDirectories)
            {
                _reader.BaseStream.Position = subdir.Offset;
                subdir.ParseDirectory();
            }
        }