热血**资源文件wzl、wzx解析
盛大**客户端的图片资源都保存在data目录下的wzl文件中,wzl文件结构比较简单,由一个文件头结构和若干图片数据组成。
找了个最小的wzl文件作为例子
蓝色高亮部分就是文件头,其中只有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文件中的偏移量
非常简单,除了file header外剩下的数据就是一个偏移量数组。
正确提取图片的方法是:
1、读取wzx文件,取出偏移量数组
2、读取wzl文件中对应的image struct
3、解压图片数据
4、根据image struct中记录的图片位深、宽高信息导出图片