Maplestory Reference Wiki
Advertisement

The WZ format is what the MapleStory client uses to store nearly all data, consisting of sound, images, strings, and numbers. It is a proprietary binary format, but it isn't too hard to parse.

Parsing a WZ File[]

Primitive types[]

The wz data is filled with all sorts of primitives. Here is a guide on how to parse them all.

Integers[]

All integers are stored using little endian. The low byte is the least significant byte. Signed integers use two's complement. No compression or encryption is used on the integers, unless otherwise specified.

The header[]

  • A 4 byte string for the ident which is always "PKG1". If a file does not begin with this, you can safely assume that it is not a wz file.
  • An 8 byte unsigned integer specifying the size of the file minus the header size.
  • A 4 byte unsigned integer specifying the size of the header.
  • The rest of the space, from the start of the file to the size of the header, is a null terminated copyright string.
struct header {
    char ident[4] = "PKG1";
    uint64 filesize;
    uint32 headersize;
    char copyright[headersize-16];
}

The version[]

The first two bytes after the header are the encrypted version. The only known way to obtain the version from the encrypted number is to brute force it. Aside from knowing what version the wz file is, the version hash is an extremely useful number as it lets you calculate the offsets of directories and imgs, rather than being forced to read everything sequentially.

uint16 encversion = readuint16()
for (uint16 version = 0; version < uint16.max; version++) {
    string str = version //Cast the base 10 version into an ascii string
    uint32 hash = 0
    for (i = 0; i < str.length; i++) {
        hash = 32*hash + str[i] + 1
    }
    uint16 result = 0xFF^(hash>>24)^(hash<<8>>24)^(hash<<16>>24)^(hash<<24>>24)
    if (result == encversion) {
        //Found possible version
    }
}

Unfortunately, the hashing algorithm is rather poor, so false positives are quite likely. The only way to reliably know for sure is to try parsing the wz file. If something isn't right, then go back and try another version.

Directories[]

The next region of data is filled with all the directories. The first directory begins immediately after the version. Each directory consists of the following.

  • A compressed int specifying the number of children in the directory. If the number is 0 then you can assume that it indicates another wz file.
  • An array of children of size count, each consisting of the following:
    • A 1 byte unsigned integer indicating the type of the child.
    • If type == 2
      • 4 byte unsigned integer offset
      • Seek to that offset + end of header
      • A new 1 byte unsigned integer to replace the old type
      • An encrypted string for the name of the child
      • Return to your position before the seek
    • If type == 3 or type == 4 (3 means the child is a directory, 4 means the child is a img)
      • An encrypted string for the name of the child
    • If type == 1, OH GOD WHAT IS THIS I DON'T EVEN
    • A compressed int indicating the size of the child
    • A compressed int indicating a checksum of the child
    • An encrypted offset indicating the location of the child

Imgs[]

Sub Properties[]

Extended Properties[]

Canvas Properties[]

[]

Advertisement