热血**资源文件wzl、wzx解析

盛大**客户端的图片资源都保存在data目录下的wzl文件中,wzl文件结构比较简单,由一个文件头结构和若干图片数据组成。

找了个最小的wzl文件作为例子

热血**资源文件wzl、wzx解析

蓝色高亮部分就是文件头,其中只有ImageCount有意义,其他的字段不清楚是做什么的,也不用关心,因为不会影响图片解析。

ImageCount表示该文件中一共有多少张图片,但是研究后发现,后面出现的图片数量不一定就是这个总数,因为有空图存在。就好比你有一个数组int arr[10],但是只用到5个元素一样。

接着后面就是若干个IMAGE结构了

typedef struct {
  byte pixelFormat;  // 图片位深
  byte compressed;   // 表示图片数据是否经过gzip压缩
  byte reserve;
  byte compressLevel; // 如果图片数据是压缩过,这个就表示压缩的等级
  short width;  // 图片宽度
  short height;  // 图片高度
  short x;
  short y;
  int size;  // 图片数据长度
} IMAGE;

结构后面紧跟着就是图片的原始数据,根据compressed可以得知这段数据是不是gzip压缩过的数据,如果是的则需要解压。

而PixelFormat指明了这张图片的位深度,它的值对应Delphi中的TPixelFormat枚举类型(因为**就是Delphi开发的)。

因为历史原因,**的图片资源基本都是8bit或16bit的位图。

bmp文件格式规定,8bit的图片颜色是由调色板来指定的,调色板是一个包含256个元素的RGBQuad数组

MirPalette: array[0..255] of TRGBQuad;

**使用的调色板数据如下(这里用C#来表示,看上去舒服点)

private static readonly Color[] MirPalette =
{
    Color.FromArgb(0, 0, 0),
    Color.FromArgb(128, 0, 0),
    Color.FromArgb(0, 128, 0),
    Color.FromArgb(128, 128, 0),
    Color.FromArgb(0, 0, 128),
    Color.FromArgb(128, 0, 128),
    Color.FromArgb(0, 128, 128),
    Color.FromArgb(192, 192, 192),
    Color.FromArgb(85, 128, 151),
    Color.FromArgb(157, 185, 200),
    Color.FromArgb(123, 115, 115),
    Color.FromArgb(45, 41, 41),
    Color.FromArgb(90, 82, 82),
    Color.FromArgb(99, 90, 90),
    Color.FromArgb(66, 57, 57),
    Color.FromArgb(29, 24, 24),
    Color.FromArgb(24, 16, 16),
    Color.FromArgb(41, 24, 24),
    Color.FromArgb(16, 8, 8),
    Color.FromArgb(242, 121, 113),
    Color.FromArgb(225, 103, 95),
    Color.FromArgb(255, 90, 90),
    Color.FromArgb(255, 49, 49),
    Color.FromArgb(214, 90, 82),
    Color.FromArgb(148, 16, 0),
    Color.FromArgb(148, 41, 24),
    Color.FromArgb(57, 8, 0),
    Color.FromArgb(115, 16, 0),
    Color.FromArgb(181, 24, 0),
    Color.FromArgb(189, 99, 82),
    Color.FromArgb(66, 24, 16),
    Color.FromArgb(255, 170, 153),
    Color.FromArgb(90, 16, 0),
    Color.FromArgb(115, 57, 41),
    Color.FromArgb(165, 74, 49),
    Color.FromArgb(148, 123, 115),
    Color.FromArgb(189, 82, 49),
    Color.FromArgb(82, 33, 16),
    Color.FromArgb(123, 49, 24),
    Color.FromArgb(45, 24, 16),
    Color.FromArgb(140, 74, 49),
    Color.FromArgb(148, 41, 0),
    Color.FromArgb(189, 49, 0),
    Color.FromArgb(198, 115, 82),
    Color.FromArgb(107, 49, 24),
    Color.FromArgb(198, 107, 66),
    Color.FromArgb(206, 74, 0),
    Color.FromArgb(165, 99, 57),
    Color.FromArgb(90, 49, 24),
    Color.FromArgb(42, 16, 0),
    Color.FromArgb(21, 8, 0),
    Color.FromArgb(58, 24, 0),
    Color.FromArgb(8, 0, 0),
    Color.FromArgb(41, 0, 0),
    Color.FromArgb(74, 0, 0),
    Color.FromArgb(157, 0, 0),
    Color.FromArgb(220, 0, 0),
    Color.FromArgb(222, 0, 0),
    Color.FromArgb(251, 0, 0),
    Color.FromArgb(156, 115, 82),
    Color.FromArgb(148, 107, 74),
    Color.FromArgb(115, 74, 41),
    Color.FromArgb(82, 49, 24),
    Color.FromArgb(140, 74, 24),
    Color.FromArgb(136, 68, 17),
    Color.FromArgb(74, 33, 0),
    Color.FromArgb(33, 24, 16),
    Color.FromArgb(214, 148, 90),
    Color.FromArgb(198, 107, 33),
    Color.FromArgb(239, 107, 0),
    Color.FromArgb(255, 119, 0),
    Color.FromArgb(165, 148, 132),
    Color.FromArgb(66, 49, 33),
    Color.FromArgb(24, 16, 8),
    Color.FromArgb(41, 24, 8),
    Color.FromArgb(33, 16, 0),
    Color.FromArgb(57, 41, 24),
    Color.FromArgb(140, 99, 57),
    Color.FromArgb(66, 41, 16),
    Color.FromArgb(107, 66, 24),
    Color.FromArgb(123, 74, 24),
    Color.FromArgb(148, 74, 0),
    Color.FromArgb(140, 132, 123),
    Color.FromArgb(107, 99, 90),
    Color.FromArgb(74, 66, 57),
    Color.FromArgb(41, 33, 24),
    Color.FromArgb(70, 57, 41),
    Color.FromArgb(181, 165, 148),
    Color.FromArgb(123, 107, 90),
    Color.FromArgb(206, 177, 148),
    Color.FromArgb(165, 140, 115),
    Color.FromArgb(140, 115, 90),
    Color.FromArgb(181, 148, 115),
    Color.FromArgb(214, 165, 115),
    Color.FromArgb(239, 165, 74),
    Color.FromArgb(239, 198, 140),
    Color.FromArgb(123, 99, 66),
    Color.FromArgb(107, 86, 57),
    Color.FromArgb(189, 148, 90),
    Color.FromArgb(99, 57, 0),
    Color.FromArgb(214, 198, 173),
    Color.FromArgb(82, 66, 41),
    Color.FromArgb(148, 99, 24),
    Color.FromArgb(239, 214, 173),
    Color.FromArgb(165, 140, 99),
    Color.FromArgb(99, 90, 74),
    Color.FromArgb(189, 165, 123),
    Color.FromArgb(90, 66, 24),
    Color.FromArgb(189, 140, 49),
    Color.FromArgb(53, 49, 41),
    Color.FromArgb(148, 132, 99),
    Color.FromArgb(123, 107, 74),
    Color.FromArgb(165, 140, 90),
    Color.FromArgb(90, 74, 41),
    Color.FromArgb(156, 123, 57),
    Color.FromArgb(66, 49, 16),
    Color.FromArgb(239, 173, 33),
    Color.FromArgb(24, 16, 0),
    Color.FromArgb(41, 33, 0),
    Color.FromArgb(156, 107, 0),
    Color.FromArgb(148, 132, 90),
    Color.FromArgb(82, 66, 24),
    Color.FromArgb(107, 90, 41),
    Color.FromArgb(123, 99, 33),
    Color.FromArgb(156, 123, 33),
    Color.FromArgb(222, 165, 0),
    Color.FromArgb(90, 82, 57),
    Color.FromArgb(49, 41, 16),
    Color.FromArgb(206, 189, 123),
    Color.FromArgb(99, 90, 57),
    Color.FromArgb(148, 132, 74),
    Color.FromArgb(198, 165, 41),
    Color.FromArgb(16, 156, 24),
    Color.FromArgb(66, 140, 74),
    Color.FromArgb(49, 140, 66),
    Color.FromArgb(16, 148, 41),
    Color.FromArgb(8, 24, 16),
    Color.FromArgb(8, 24, 24),
    Color.FromArgb(8, 41, 16),
    Color.FromArgb(24, 66, 41),
    Color.FromArgb(165, 181, 173),
    Color.FromArgb(107, 115, 115),
    Color.FromArgb(24, 41, 41),
    Color.FromArgb(24, 66, 74),
    Color.FromArgb(49, 66, 74),
    Color.FromArgb(99, 198, 222),
    Color.FromArgb(68, 221, 255),
    Color.FromArgb(140, 214, 239),
    Color.FromArgb(115, 107, 57),
    Color.FromArgb(247, 222, 57),
    Color.FromArgb(247, 239, 140),
    Color.FromArgb(247, 231, 0),
    Color.FromArgb(107, 107, 90),
    Color.FromArgb(90, 140, 165),
    Color.FromArgb(57, 181, 239),
    Color.FromArgb(74, 156, 206),
    Color.FromArgb(49, 132, 181),
    Color.FromArgb(49, 82, 107),
    Color.FromArgb(222, 222, 214),
    Color.FromArgb(189, 189, 181),
    Color.FromArgb(140, 140, 132),
    Color.FromArgb(247, 247, 222),
    Color.FromArgb(0, 8, 24),
    Color.FromArgb(8, 24, 57),
    Color.FromArgb(8, 16, 41),
    Color.FromArgb(8, 24, 0),
    Color.FromArgb(8, 41, 0),
    Color.FromArgb(0, 82, 165),
    Color.FromArgb(0, 123, 222),
    Color.FromArgb(16, 41, 74),
    Color.FromArgb(16, 57, 107),
    Color.FromArgb(16, 82, 140),
    Color.FromArgb(33, 90, 165),
    Color.FromArgb(16, 49, 90),
    Color.FromArgb(16, 66, 132),
    Color.FromArgb(49, 82, 132),
    Color.FromArgb(24, 33, 49),
    Color.FromArgb(74, 90, 123),
    Color.FromArgb(82, 107, 165),
    Color.FromArgb(41, 57, 99),
    Color.FromArgb(16, 74, 222),
    Color.FromArgb(41, 41, 33),
    Color.FromArgb(74, 74, 57),
    Color.FromArgb(41, 41, 24),
    Color.FromArgb(74, 74, 41),
    Color.FromArgb(123, 123, 66),
    Color.FromArgb(156, 156, 74),
    Color.FromArgb(90, 90, 41),
    Color.FromArgb(66, 66, 20),
    Color.FromArgb(57, 57, 0),
    Color.FromArgb(89, 89, 0),
    Color.FromArgb(202, 53, 44),
    Color.FromArgb(107, 115, 33),
    Color.FromArgb(41, 49, 0),
    Color.FromArgb(49, 57, 16),
    Color.FromArgb(49, 57, 24),
    Color.FromArgb(66, 74, 0),
    Color.FromArgb(82, 99, 24),
    Color.FromArgb(90, 115, 41),
    Color.FromArgb(49, 74, 24),
    Color.FromArgb(24, 33, 0),
    Color.FromArgb(24, 49, 0),
    Color.FromArgb(24, 57, 16),
    Color.FromArgb(99, 132, 74),
    Color.FromArgb(107, 189, 74),
    Color.FromArgb(99, 181, 74),
    Color.FromArgb(99, 189, 74),
    Color.FromArgb(90, 156, 74),
    Color.FromArgb(74, 140, 57),
    Color.FromArgb(99, 198, 74),
    Color.FromArgb(99, 214, 74),
    Color.FromArgb(82, 132, 74),
    Color.FromArgb(49, 115, 41),
    Color.FromArgb(99, 198, 90),
    Color.FromArgb(82, 189, 74),
    Color.FromArgb(16, 255, 0),
    Color.FromArgb(24, 41, 24),
    Color.FromArgb(74, 136, 74),
    Color.FromArgb(74, 231, 74),
    Color.FromArgb(0, 90, 0),
    Color.FromArgb(0, 136, 0),
    Color.FromArgb(0, 148, 0),
    Color.FromArgb(0, 222, 0),
    Color.FromArgb(0, 238, 0),
    Color.FromArgb(0, 251, 0),
    Color.FromArgb(74, 90, 148),
    Color.FromArgb(99, 115, 181),
    Color.FromArgb(123, 140, 214),
    Color.FromArgb(107, 123, 214),
    Color.FromArgb(119, 136, 255),
    Color.FromArgb(198, 198, 206),
    Color.FromArgb(148, 148, 156),
    Color.FromArgb(156, 148, 198),
    Color.FromArgb(49, 49, 57),
    Color.FromArgb(41, 24, 132),
    Color.FromArgb(24, 0, 132),
    Color.FromArgb(74, 66, 82),
    Color.FromArgb(82, 66, 123),
    Color.FromArgb(99, 90, 115),
    Color.FromArgb(206, 181, 247),
    Color.FromArgb(140, 123, 156),
    Color.FromArgb(119, 34, 204),
    Color.FromArgb(221, 170, 255),
    Color.FromArgb(240, 180, 42),
    Color.FromArgb(223, 0, 159),
    Color.FromArgb(227, 23, 179),
    Color.FromArgb(255, 251, 240),
    Color.FromArgb(160, 160, 164),
    Color.FromArgb(128, 128, 128),
    Color.FromArgb(255, 0, 0),
    Color.FromArgb(0, 255, 0),
    Color.FromArgb(255, 255, 0),
    Color.FromArgb(0, 0, 255),
    Color.FromArgb(255, 0, 255),
    Color.FromArgb(0, 255, 255),
    Color.FromArgb(255, 255, 255)
};

而对于16bit的图片来说,又有几种颜色模式之分,我们这里只需要知道,**的16bit图是用的RGB565模式。

至此,wzl文件差不多就这样了,是不是可以解析了?不是,因为上面说过,图片和图片之间可能存在空图,而空图不仅只是一个image header而已,后面可能跟着若干字节数据(不清楚这个数据有什么用),而这个长度也没办法知道,所以单单靠wzl一个文件想提取图片和其对应的索引号是不可能的,于是wzx文件诞生了。

wzx文件非常简单,就是一个索引数组,记录每张图片在wzl文件中的偏移量

热血**资源文件wzl、wzx解析

非常简单,除了file header外剩下的数据就是一个偏移量数组。

正确提取图片的方法是:

1、读取wzx文件,取出偏移量数组

2、读取wzl文件中对应的image struct

3、解压图片数据

4、根据image struct中记录的图片位深、宽高信息导出图片