MPQ Storm库 源代码分析 一个

MPQ Storm库 源代码分析 一个

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。


MPQ什么?

        MPQ维基上说的非常明确。

简而言之,它是暴雪公司用于游戏数据打包的工具。星际争霸,魔兽争霸游戏中都有使用。该工具内含游戏资源加密和压缩等功能。
        git下载地址:https://github.com/stormlib/StormLib

        MPQ文件总共同拥有四种格式:

             第一种:FLAT格式。线性存储。

             另外一种:Partial格式,分包的存储。

             第三种:MPQE格式,加密存储。

             第四种:BLOCK格式。模块存储。

        

FLAT格式最简单。只是该格式也支持对单个文件的加密和压缩。

本文主要分析FLAT格式,主要包括下面五点:

        一、创建一个MPQ文件。

        、加入资源文件。

        、封装MPQ文件。

        四、读取MPQ文件。

        五、读取资源文件。

        图一、图二、图三为FLAT格式的内部格式。

MPQ Storm库 源代码分析 一个

图一

        、创建一个MPQ文件。

             主要过程是。调用SFileCreateArchive接口创建MPQ文件。创建成功之后,该接口会返回成功与否。同一时候将MPQ文件的句柄赋值给传进来的变量。

             创建MPQ文件具体流程是:

             1》在内存中初始化一个加密块StormBuffer;

             2》尝试打开一个同名的MPQ文件。假如已经存在的同名文件不是MPQ文件,MPQ工具就会尝试用MPQ文件的格式读取该文件。为了避免同名的错误。在StormLib的样例中,有先删除同一文件夹想的同名文件,再创建MPQ文件的逻辑。

             3》创建一个空的MPQ文件。

             4》重置文件大小。

             5》写入一个假的MPQ文件头部,即图一的A指向的区域。

MPQ的头部有四种不同的格式。分别拥有不同的长度,只是默认有一个最大长度是208字节。写这个假的MPQ文件头部,最基本的目的是占位,保证第一个数据文件的写入位置是在正确的。

             6》假设是大文件,则创建大文件的索引表HetTable。

             7》创建HashTabl,用来索引文件的。

             以上七个过程。主要实现了两个结果,1、创建了MPQ文件,2、在内存中生成须要用到的MPQ数据。


        二、加入资源文件。

             主要过程是,调用SFileCreateFile接口。在MPQ文件里创建一个新的文件句柄。通过SFileWriteFile接口写入数据。

调用SFileCloseFile释放内存资源。

             具体流程:

             1》检查是不是内部文件。MPQ主要有两个内部文件,一个是listfile。另外一个attributes。假设不是内部文件,则向MPQ文件里加入新的文件。

             2》找到MPQ文件里能够写入的位置。假设是第一次写入。则此时是图一B指向的区域。

但此时还没有写入。

             3》通过HashString方法,将资源文件名称转化为hash索引值。以新的hash索引值从当前的HashTable中取一个TMPQHash数据结构。

             4》假如不是第一次建立新文件。则此时,通过TMPQHash的dwBlockIndex值。在FileTable做dwBlockIndex偏移。获取新文件的入口TFileEntry。假如是第一次建立新文件。则会先到FileTable里面取出一个空暇的位置,分配一个TFileEntry。默认是取FileTable位置做dwFileTableSize偏移,而此时dwFileTableSize值是0,所以就是FileTable表中第一个位置。即图一B指向的区域

同一时候分配一个TMPQHash(hash索引的取值与文件名称有关),分配完之后。与FileEntry关联。在FileEntry里通过dwHashIndex索引到hash表中的位置,TMPQHash通过dwBlockIndex索引到FileEntry。

             5》拿到了FileEntry以后,在SFileAddFile_Init函数中初始化FileEntry的其它值。

经过这些逻辑。就能够拿到一个TMPQFile文件指针,用来写入数据。

             6》通过SFileWriteFile接口写入文件数据,能够将资源文件分批写到MPQ文件里。也能够将资源文件一次写入MPQ文件里,两种都不会有问题。

MPQ Storm库 源代码分析 一个

图二


             7》在将要写文件的前,会先写入一个扇区,默认有8字节,扇区与将要写入的数据的加密有关联。然后写入

数据,数据有选项,能够选择是否加密,是否压缩,是否选择数据作为单元文件存储。

写入完成之后,会再次写入当

前扇区,详细为什么要两次写入扇区,下一篇会继续分析。图二中。L指向的是真正的资源文件数据,K、M各自是扇

区。资源文件可选择加密和压缩。


MPQ Storm库 源代码分析 一个

图三


        三、封装MPQ文件。
        封装挺重要的,封装时会将新生成的文件相关的数据更新到MPQ文件头部。覆盖原先的假头部。

封装的主要过程是。将与文件相关的HET表和BET表,以及HASH表,文件FileTable。按顺序写到最后一个资源文件的结尾位置。

封装逻辑运行完之后。新的MPQ文件内部结构如图三。
        详细流程是:                
             1》确定是否要写入listfile、attributes等文件,假设要,则会在MPQ文件里创建,并写入。
             2》调用SFileCloseArchive,找到能够写入HET、BET、HASH、FILETABLE表的位置,然后将这些表的数据写入到新的MPQ文件里。写入后MPQ文件内部如图三。表的数据会写在第N个数据文件之后。最后,回到头部更新MPQ文件头部。

             3》释放内存中的资源。


        四、读取MPQ文件。

        主要流程是。打开MPQ文件,先读取头部。在读取正确之后,解析各个表的位置。获取数据文件位置。而且随意一个环节出错。都会退出。
        详细流程:
             1》初始化一个StormBuff(与数据加密有关)。然后用208字节的长度,从MPQ文件头部0位置開始读取,一次读取208字节。

读取完之后强制转化为TMPQHeader数据结构。

TMPQHeader内部的数据是正确的,则開始读取文件,为了推断文件是否正确,MPQ会有很多检測。只是MPQ文件头部默认有四种格式。

每一种格式的长度都不一样。在确定头部之后。会调用memset。将超出的部分置0,确保新生成的MPQHeader数据正确。

             2》通过新获得的头部数据结构。读取HASH表。Hash表通过TMPQHeader的dwHashTablePos属性。找到其在文件里的位置,并读取出。接着将文件里的数据,读取到内存里面,完毕Hash表数据的读取。

             3》建立文件数据表。通过读取Hash表,初始化文件数据表FileTable。有了FileTable就能够得到FileEntry,有了文件入口。就能读取数据了

             4》加载listfile和attributes文件。

眼下我没用到这两个选项。

             5》返回MPQ文件句柄。

        五、读取资源文件。
        有两种读取方式。

第一种是取出当中某一个特定的文件,另外一种遍历MPQ文件内部全部的数据文件。
        第一种取出一个文件是比較简单的。
        详细流程是:
             1》调用SFileOpenFileEx接口(Ex即外部文件的意思)。传入文件名称给该接口,接口内部会将文件名称转化为hash数据。通过hash数据的dwBlockIndex属性,算出FileEntry数据,有了FileEntry,就能够获得要读取的文件的数据的位置。而且获取该数据文件的句柄。也能够先调用SFileHasFile推断是否有该文件。

             2》调用SFileGetFileSize获取文件大小,申请内存空间。调用SFileGetFileInfo获取文件信息,不是数据。
             3》调用SFileReadFile获取MPQ文件里特定资源文件的数据。

             4》调用SFileCloseFile释放申请的内存。

        另外一种略微复杂一些。
        详细流程是:
             1》调用SFileFindFirstFile,匹配符为*,则会所有匹配。返回一个hFind值。

             2》运行读取一个文件的流程,上面已经说明,此处不再赘述。
             3》调用SFileFindNextFile获取下一个文件的入口。

             4》循环运行1==>3流程。直至没有文件能够读取。



版权声明:本文博客原创文章,博客,未经同意,不得转载。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/117250.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • web前端开发面试中常见的算法题(JS)

    web前端开发面试中常见的算法题(JS)前言最近在准备秋招,做过了大大小小的公司的面试题,发现除了基础知识外,算法还是挺重要的。特意整理了一些常见的算法题,添加了自己的理解并实现。除此之外,建议大家还可以刷刷《剑指offer》(但我还没刷完?,任重道远呐)。此外,左神在牛客网上也有算法课程,听了基础班的感觉还不错,起码让我这个算法小白也能快速地理解了很多问题,知识付费的时代,这个真的是良心课程了。就我个人而言的话,平时为了解决一…

  • SQL报错注入_报错注入原理

    SQL报错注入_报错注入原理目录1报错注入概述2常用的报错注入命令2.2groupby重复键冲突(count()+floor()+rand()+groupby组合)2.2.1groupby重复键冲突的原理及bug演示2.2.2补充:sql语句解析过程2.3XPATH报错2.3.1extractvalue()函数2.3.2updatexml()函数2.4测试失败的命令3报错注入案例3.1操作环境3.2获取敏感信息3.2.1获取数据库名3.2.2获取表名3.2.3获取字段名3.2.4获取字段内

  • 大学本科数学专业课程有哪些(数学专业大一上学期课程)

    专业基础类课程:解析几何(大一上学期)数学分析I(大一上学期)数学分析II(大一下学期)数学分析III(大二上学期)高等代数I(大一上学期)高等代数II(大一下学期)常微分方程(大二上学期)抽象代数(大二下学期)概率论基础(大二下学期)复变函数(大二下学期)近世代数(大二下学期)专业核心课程:实变函数(大三上学期)偏微分方程(大三上学期)概率论(大三上…

  • ADRC例程

    ADRC例程ADRC优化fhan《自抗扰控制入门》自抗扰死忠粉ADRC.H#ifndef_ADRC_H_#define_ADRC_H_typedefstruct{/*****安排过度过程*******/floatx1;//跟踪微分期状态量floatx2;//跟踪微分期状态量微分项floatr;//时间尺度floath;//ADRC系统积分时间uint16N0;/…

  • Java构造函数调用顺序问题

    Java构造函数调用顺序问题java构造代码调用顺序研究。

  • CAS单点登录原理(包含详细流程,讲得很透彻,耐心看下去一定能看明白!)

    CAS单点登录原理(包含详细流程,讲得很透彻,耐心看下去一定能看明白!)转载地址http://www.cnblogs.com/lihuidu/p/6495247.html1、基于Cookie的单点登录的回顾    基于Cookie的单点登录核心原理:   将用户名密码加密之后存于Cookie中,之后访问网站时在过滤器(filter)中校验用户权限,如果没有权限则从Cookie中取出用户名密码进行登录,让用户从某种意义上觉得只登录了一次。   该方式缺…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号