Exemple #1
0
        internal void DumpBlock(int endOfBlock, string name)
        {
            switch (reader.ReadByte())
            {
            case 0x1B:
                ExtractMore(endOfBlock, name, reader.ReadStringAtOffset(offset + reader.ReadInt32()));
                return;

            case 0x73:
                ExtractMore(endOfBlock, name, "");
                return;
            }
        }
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
        /// <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 #4
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>
        /// 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;
        }
Exemple #6
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 == 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;
                }
                reader.BaseStream.Position = rememberPos;
                fsize    = reader.ReadCompressedInt();
                checksum = reader.ReadCompressedInt();
                offset   = reader.ReadOffset();
                if (type == 3)
                {
                    WzDirectory subDir = new WzDirectory(reader, fname, hash, WzIv);
                    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 #7
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);
 }
Exemple #9
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);
            }
        }
Exemple #10
0
        internal WzPngProperty(WzBinaryReader pReader)
        {
            // Read compressed bytes
            mWidth   = pReader.ReadCompressedInt();
            mHeight  = pReader.ReadCompressedInt();
            mFormat  = pReader.ReadCompressedInt();
            mFormat2 = pReader.ReadByte();
            pReader.BaseStream.Position += 4;
            mOffsets = pReader.BaseStream.Position;
            int len = pReader.ReadInt32() - 1;

            pReader.BaseStream.Position += 1;

            if (len > 0)
            {
                pReader.BaseStream.Position += len;
            }
            mWzReader = pReader;
        }
        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;
        }
Exemple #12
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);
         }
     }
 }
Exemple #13
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();
            }
        }
Exemple #14
0
        internal static AWzImageProperty ParseExtendedProp(WzBinaryReader pReader, uint pOffset, int pEndOfBlock, string pName, AWzObject pParent, WzImage pImgParent)
        {
            byte b = pReader.ReadByte();

            switch (b)
            {
            case 0x1B:
                return(ExtractMore(pReader, pOffset, pEndOfBlock, pName, pReader.ReadStringAtOffset(pOffset + pReader.ReadInt32()), pParent, pImgParent));

            case 0x73:
                return(ExtractMore(pReader, pOffset, pEndOfBlock, pName, pReader.ReadString(), pParent, pImgParent));

            default:
                return(null);
                //throw new Exception("Invlid type at ParseExtendedProp: " + b);
            }
        }
Exemple #15
0
        internal static AWzImageProperty ExtractMore(WzBinaryReader pReader, uint pOffset, int pEndOfBlock, string pName, string pImageName, AWzObject pParent, WzImage pImgParent)
        {
            switch (pImageName)
            {
            case "Property":
                WzSubProperty subProp = new WzSubProperty(pName)
                {
                    Parent = pParent, ParentImage = pImgParent
                };
                pReader.BaseStream.Position += 2;
                subProp.AddProperties(ParsePropertyList(pOffset, pReader, subProp, pImgParent));
                return(subProp);

            case "Canvas":
                WzCanvasProperty canvasProp = new WzCanvasProperty(pName)
                {
                    Parent = pParent, ParentImage = pImgParent
                };
                pReader.BaseStream.Position++;
                if (pReader.ReadByte() == 1)
                {
                    pReader.BaseStream.Position += 2;
                    canvasProp.AddProperties(ParsePropertyList(pOffset, pReader, canvasProp, pImgParent));
                }
                canvasProp.PngProperty = new WzPngProperty(pReader)
                {
                    Parent = canvasProp, ParentImage = pImgParent
                };
                return(canvasProp);

            case "Shape2D#Vector2D":
                WzVectorProperty vecProp = new WzVectorProperty(pName)
                {
                    Parent = pParent, ParentImage = pImgParent
                };
                vecProp.X = new WzCompressedIntProperty("X", pReader.ReadCompressedInt())
                {
                    Parent = vecProp, ParentImage = pImgParent
                };
                vecProp.Y = new WzCompressedIntProperty("Y", pReader.ReadCompressedInt())
                {
                    Parent = vecProp, ParentImage = pImgParent
                };
                return(vecProp);

            case "Shape2D#Convex2D":
                WzConvexProperty convexProp = new WzConvexProperty(pName)
                {
                    Parent = pParent, ParentImage = pImgParent
                };
                int convexEntryCount = pReader.ReadCompressedInt();
                for (int i = 0; i < convexEntryCount; i++)
                {
                    AWzImageProperty imgProp = ParseExtendedProp(pReader, pOffset, 0, pName, convexProp, pImgParent);
                    if (imgProp != null)
                    {
                        convexProp.AddProperty(imgProp);
                    }
                }
                return(convexProp);

            case "Sound_DX8":
                WzSoundProperty soundProp = new WzSoundProperty(pName)
                {
                    Parent = pParent, ParentImage = pImgParent
                };
                soundProp.ParseSound(pReader);
                return(soundProp);

            case "UOL":
                pReader.BaseStream.Position++;
                byte b = pReader.ReadByte();
                switch (b)
                {
                case 0:
                    return(new WzUOLProperty(pName, pReader.ReadString())
                    {
                        Parent = pParent, ParentImage = pImgParent
                    });

                case 1:
                    return(new WzUOLProperty(pName, pReader.ReadStringAtOffset(pOffset + pReader.ReadInt32()))
                    {
                        Parent = pParent, ParentImage = pImgParent
                    });

                default:
                    throw new Exception("Unsupported UOL type: " + b);
                }

            default:
                throw new Exception("Unknown image name: " + pImageName);
            }
        }
Exemple #16
0
        internal static IExtended ExtractMore(WzBinaryReader reader, uint offset, int eob, string name, string iname, IWzObject parent, WzImage imgParent)
        {
            if (iname == "")
            {
                iname = reader.ReadString();
            }
            switch (iname)
            {
            case "Property":
                WzSubProperty subProp = new WzSubProperty(name)
                {
                    Parent = parent
                };
                reader.BaseStream.Position += 2;
                subProp.AddProperties(IWzImageProperty.ParsePropertyList(offset, reader, subProp, imgParent));
                return(subProp);

            case "Canvas":
                WzCanvasProperty canvasProp = new WzCanvasProperty(name)
                {
                    Parent = parent
                };
                reader.BaseStream.Position++;
                if (reader.ReadByte() == 1)
                {
                    reader.BaseStream.Position += 2;
                    canvasProp.AddProperties(IWzImageProperty.ParsePropertyList(offset, reader, canvasProp, imgParent));
                }
                canvasProp.PngProperty = new WzPngProperty(reader, imgParent.parseEverything)
                {
                    Parent = canvasProp
                };
                return(canvasProp);

            case "Shape2D#Vector2D":
                WzVectorProperty vecProp = new WzVectorProperty(name)
                {
                    Parent = parent
                };
                vecProp.X = new WzCompressedIntProperty("X", reader.ReadCompressedInt())
                {
                    Parent = vecProp
                };
                vecProp.Y = new WzCompressedIntProperty("Y", reader.ReadCompressedInt())
                {
                    Parent = vecProp
                };
                return(vecProp);

            case "Shape2D#Convex2D":
                WzConvexProperty convexProp = new WzConvexProperty(name)
                {
                    Parent = parent
                };
                int convexEntryCount = reader.ReadCompressedInt();
                convexProp.WzProperties.Capacity = convexEntryCount;     //performance thing
                for (int i = 0; i < convexEntryCount; i++)
                {
                    convexProp.AddProperty(ParseExtendedProp(reader, offset, 0, name, convexProp, imgParent));
                }
                return(convexProp);

            case "Sound_DX8":
                WzSoundProperty soundProp = new WzSoundProperty(name, reader, imgParent.parseEverything)
                {
                    Parent = parent
                };
                return(soundProp);

            case "UOL":
                reader.BaseStream.Position++;
                switch (reader.ReadByte())
                {
                case 0:
                    return(new WzUOLProperty(name, reader.ReadString())
                    {
                        Parent = parent
                    });

                case 1:
                    return(new WzUOLProperty(name, reader.ReadStringAtOffset(offset + reader.ReadInt32()))
                    {
                        Parent = parent
                    });
                }
                throw new Exception("Unsupported UOL type");

            default:
                throw new Exception("Unknown iname: " + iname);
            }
        }
Exemple #17
0
        internal static IExtended ParseExtendedProp(WzBinaryReader reader, uint offset, int endOfBlock, string name, IWzObject parent, WzImage imgParent)
        {
            switch (reader.ReadByte())
            {
            case 0x1B:
                return(ExtractMore(reader, offset, endOfBlock, name, reader.ReadStringAtOffset(offset + reader.ReadInt32()), parent, imgParent));

            case 0x73:
                return(ExtractMore(reader, offset, endOfBlock, name, "", parent, imgParent));

            default:
                throw new System.Exception("Invlid byte read at ParseExtendedProp");
            }
        }
Exemple #18
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 #19
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();
            }
        }
Exemple #20
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();
                }
            }
        }