您的位置:首页 > 其它

.osr 文件格式解析(五) - 回放数据ReplayData

2016-05-16 18:50 381 查看
按照ppy的描述,ReplayData是经过Lzma压缩后的数据,压缩前也是一串逗号分隔的字符串。

LZMA

LZMA简介

以下摘自7-Zip官网

LZMA是7-Zip程序中7z格式的默认压缩算法。LZMA能提供给用户极高的压缩比及较快的压缩速度,它非常适合与应用程序集成。

压缩速度在双核处理器上可以达到 2 MB/秒。

解压缩速度在英特尔酷睿2 或 AMD 速龙 64 上可以达到 20-30 MB/秒。

较小的解压缩内存需求:8-32 KB(依赖于字典大小)

较小的解压缩代码:2-8 KB

LZMA 解码器仅使用整数运算,可以在任何主流的 32 位处理器(或在一定条件下的 16 或处理器)下运行。

LZMA SDK

SDK下载LZMA SDK

LzmaLib编译

解压SDK后,在C\Util\LzmaLib下可以找到LzmaLib.dsw工程,VC6可以编译通过,生成LZMA.lib和LZMA.dll(如果没改输出路径,dll可能在C盘根目录)。然后把LzmaLib.h、Types.h、LZMA.lib和LZMA.dll复制到自己工程的根目录,准备工作就可以说是完成了。

LZMA的使用

LZMA就2个函数,一个用于压缩,一个用于解压:

MY_STDAPI LzmaCompress(…);

MY_STDAPI LzmaUncompress(…);

在要使用lzma的地方,加上如下代码,就可以了

#include "LzmaLib.h"
#pragma comment(lib,"LZMA.lib")


LzmaCompress

std::string str="aaabbbcccdddeee";      //假定要压缩的字符串

byte *src = (byte*)str.c_str();         //原始数据的字节数组
size_t srcLen = str.length();           //原始数据的长度
size_t destLen = str.length();          //输出数据的长度
byte *dest = new byte[destLen];         //储存压缩结果的数组
byte props[5] = { 0 };                  //5字节props数据
size_t propsSize = LZMA_PROPS_SIZE;     //props的长度,LZMA_PROPS_SIZE=5

ZeroMemory(dest, destLen);

//LzmaCompress压缩
//LzmaCompress 有很多压缩参数,使用默认值则填-1,具体的参数说明见LzmaLib.h
int res = LzmaCompress(dest, &destLen, src, srcLen, props, &propsSize, -1, 1 << 24 ,- 1, -1, -1, -1, -1);

////res返回值校验,返回0则表示压缩成功
//switch (res)
//{
//case SZ_OK:                   //0 - OK
//case SZ_ERROR_DATA:           //1 - Data error

a566
//case SZ_ERROR_MEM:            //2 - Memory allocation arror
//case SZ_ERROR_UNSUPPORTED:    //4 - Unsupported properties
//case SZ_ERROR_INPUT_EOF:      //6 - it needs more bytes in input buffer(src)
//  break;
//}


压缩完毕后,dest里的就是压缩后的数据,destLen则是压缩后的长度,props里记录了压缩时所选的参数。

Lzma数据的保存

通常用以下结构来将压缩后结构保存到文件:

struct LzmaData{
int lzmaLength;
byte props[5];
__int64 srcLen;
byte *dest;
}


经LzmaCompress压缩后,props、srcLen和dest,这三样数据都是需要保留的,在解压时要依靠着三部分的数据来完成解压。LzmaLength则是三部分数据加起来的长度。

LzmaUncompress

LzmaData lzmaData;                      //假如已经从文件中读取了要解压的数据

byte *src = (byte*)data.dest;           //获取要解压的数据的字节数组
size_t srcLen = data.lzmaLength-13;     //解压数据的长度(总数据长度减去props和srcLen的长得,即减13)
size_t destLen = data.srcLen;           //压缩文件原来的长度(解压后的大小)
byte *dest = new byte[destLen];         //用来保存解压后的数据
byte *props = data.props;               //5字节props数据
size_t propsSize = LZMA_PROPS_SIZE;     //props的长度,LZMA_PROPS_SIZE=5

ZeroMemory(dest, destLen);

int res = LzmaUncompress(dest, &destLen, src, &srcLen, props, propsSize);


解压后dest里即是原本的数据。

ReplayData

运用Lzma算法我们就可以把第三章取出来的int ReplayDataLength和byte *ReplayData还原成原来的数据了。

其中:

- LzmaData.lzmaLength对应int ReplayDataLength

- LzmaData.props对应ReplayData[0-4]字节

- LzmaData.srcLen对应ReplayData[5-12]字节

- LzmaData.dest 对应ReplayData[13]以后剩下字节

(其实,如果内存对齐是1的话,可以对整块数据进行内存拷贝的)

真正的回放数据————osrReplayData

我们从ReplayData中得到了dest,这也是个文本,形如 w | x | y | z这样的以逗号分隔的数据。

所有使用和osrLifeBar一样的方式用split进行分割就好了,这里就不再赘述了。

osrReplayData定义如下:

struct osrReplayData
{
__int64 delay;  //距离上个动作的时间(毫秒)
float X;        //鼠标的X坐标(从0到512)
float Y;        //鼠标的Y坐标(从0到384)
int key;        //鼠标、键盘按键的组合 (M1 = 1, M2 = 2, K1 = 5, K2 = 10)
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: