simakuangbiao 发表于 2020-12-22 09:26

OGRE资源管理器源代码

      大家好,我是表哥。
      最近组里需要汉化金发美女(So Blonde),通过分析资源包格式,写了一个OGRE资源管理器程序(控制台程序),实现了解包、打包、汉化补丁打包等功能,其源代码分享如下,供感兴趣的坛友学习交流:
program SMKB_1;

{$APPTYPE CONSOLE}

{$R *.res}

{$WeakLinkRTTI on}
{$RTTI Explicit Methods([]) Properties([]) Fields([])}

{$R *.dres}

uses
System.SysUtils,
System.Classes,
System.IOUtils,
System.IniFiles,
Vcl.Grids,
System.Types;

//显示帮助信息
procedure ShowHelp();
begin
Writeln('-----------------------------------------------------------------');
Writeln('【ORGE资源管理器 0.1.20201208】,程序开发:表哥');
Writeln('Object-Oriented Graphics Rendering Engine Resource Manager');
Writeln('');
Writeln('使用用法:SMKB_1.exe "*.config"');
Writeln('');
Writeln('(注意:【】内的文字仅用于此处的帮助说明,在实际配置文件中不存在)');
Writeln('解包用配置文件(unpackage.config)格式:');
Writeln('');
Writeln('types=unpackage【指明此配置文件用于解包】');
Writeln('sources=d:\xxx.toc【指定全路径资源包文件名称】');
Writeln('targets=d:\demo\【指定全路径解包存储文件夹名称】');
Writeln('');
Writeln('打包用配置文件(package.config)格式:');
Writeln('');
Writeln('types=package【指明此配置文件用于打包】');
Writeln('sources=d:\demo\【指定全路径包含等待打包的资源文件夹名称】');
Writeln('targets=d:\game\【指定全路径打包存储文件夹名称】');
Writeln('');
Writeln('汉化补丁打包用配置文件(patch.config)格式:');
Writeln('');
Writeln('types=patch【指明此配置文件用于汉化补丁打包】');
Writeln('sources=d:\demo\【指定全路径包含已汉化的资源文件夹名称】');
Writeln('targets=d:\game\【指定全路径汉化补丁存储文件夹名称】');
Writeln('-----------------------------------------------------------------');
end;

//加载参数(配置文件)信息
procedure LoadConfigParam(var Types:string;var Sources:string;var Targets:string);
begin
var configFilename:string:=ParamStr(1);//获取命令行参数(配置文件)
if not configFilename.Contains(':') then configFilename:=GetCurrentDir+'\'+configFilename;//补全路径信息
//加载配置文件
var configFile:Tinifile:=nil;
if TFile.Exists(configFilename) then configFile:=TIniFile.Create(configFilename);
//解析参数信息
if configFile<>nil then
begin
    Types:=configFile.ReadString('SMKB','types','');
    Sources:=configFile.ReadString('SMKB','sources','');
    Targets:=configFile.ReadString('SMKB','targets','');
    configFile.Free();
end;
end;

//获取定长字符串
function GetFixString(Value:UInt32):string;
begin
Result:=Value.ToString();
if (5-Length(Result))>0 then for var i:Integer:=1 to 5-Length(Result) do Result:='0'+Result;
end;

//获取crc32校验值
procedure GetCRC32(PathFilename:string;var CRC32:UInt32);
const
crc32CodeTable:array of UInt32=//CRC32编码表
    ($00000000,$77073096,$EE0E612C,$990951BA,$076DC419,$706AF48F,$E963A535,$9E6495A3,$0EDB8832,$79DCB8A4,$E0D5E91E,$97D2D988,$09B64C2B,$7EB17CBD,$E7B82D07,$90BF1D91,
    $1DB71064,$6AB020F2,$F3B97148,$84BE41DE,$1ADAD47D,$6DDDE4EB,$F4D4B551,$83D385C7,$136C9856,$646BA8C0,$FD62F97A,$8A65C9EC,$14015C4F,$63066CD9,$FA0F3D63,$8D080DF5,
    $3B6E20C8,$4C69105E,$D56041E4,$A2677172,$3C03E4D1,$4B04D447,$D20D85FD,$A50AB56B,$35B5A8FA,$42B2986C,$DBBBC9D6,$ACBCF940,$32D86CE3,$45DF5C75,$DCD60DCF,$ABD13D59,
    $26D930AC,$51DE003A,$C8D75180,$BFD06116,$21B4F4B5,$56B3C423,$CFBA9599,$B8BDA50F,$2802B89E,$5F058808,$C60CD9B2,$B10BE924,$2F6F7C87,$58684C11,$C1611DAB,$B6662D3D,
    $76DC4190,$01DB7106,$98D220BC,$EFD5102A,$71B18589,$06B6B51F,$9FBFE4A5,$E8B8D433,$7807C9A2,$0F00F934,$9609A88E,$E10E9818,$7F6A0DBB,$086D3D2D,$91646C97,$E6635C01,
    $6B6B51F4,$1C6C6162,$856530D8,$F262004E,$6C0695ED,$1B01A57B,$8208F4C1,$F50FC457,$65B0D9C6,$12B7E950,$8BBEB8EA,$FCB9887C,$62DD1DDF,$15DA2D49,$8CD37CF3,$FBD44C65,
    $4DB26158,$3AB551CE,$A3BC0074,$D4BB30E2,$4ADFA541,$3DD895D7,$A4D1C46D,$D3D6F4FB,$4369E96A,$346ED9FC,$AD678846,$DA60B8D0,$44042D73,$33031DE5,$AA0A4C5F,$DD0D7CC9,
    $5005713C,$270241AA,$BE0B1010,$C90C2086,$5768B525,$206F85B3,$B966D409,$CE61E49F,$5EDEF90E,$29D9C998,$B0D09822,$C7D7A8B4,$59B33D17,$2EB40D81,$B7BD5C3B,$C0BA6CAD,
    $EDB88320,$9ABFB3B6,$03B6E20C,$74B1D29A,$EAD54739,$9DD277AF,$04DB2615,$73DC1683,$E3630B12,$94643B84,$0D6D6A3E,$7A6A5AA8,$E40ECF0B,$9309FF9D,$0A00AE27,$7D079EB1,
    $F00F9344,$8708A3D2,$1E01F268,$6906C2FE,$F762575D,$806567CB,$196C3671,$6E6B06E7,$FED41B76,$89D32BE0,$10DA7A5A,$67DD4ACC,$F9B9DF6F,$8EBEEFF9,$17B7BE43,$60B08ED5,
    $D6D6A3E8,$A1D1937E,$38D8C2C4,$4FDFF252,$D1BB67F1,$A6BC5767,$3FB506DD,$48B2364B,$D80D2BDA,$AF0A1B4C,$36034AF6,$41047A60,$DF60EFC3,$A867DF55,$316E8EEF,$4669BE79,
    $CB61B38C,$BC66831A,$256FD2A0,$5268E236,$CC0C7795,$BB0B4703,$220216B9,$5505262F,$C5BA3BBE,$B2BD0B28,$2BB45A92,$5CB36A04,$C2D7FFA7,$B5D0CF31,$2CD99E8B,$5BDEAE1D,
    $9B64C2B0,$EC63F226,$756AA39C,$026D930A,$9C0906A9,$EB0E363F,$72076785,$05005713,$95BF4A82,$E2B87A14,$7BB12BAE,$0CB61B38,$92D28E9B,$E5D5BE0D,$7CDCEFB7,$0BDBDF21,
    $86D3D2D4,$F1D4E242,$68DDB3F8,$1FDA836E,$81BE16CD,$F6B9265B,$6FB077E1,$18B74777,$88085AE6,$FF0F6A70,$66063BCA,$11010B5C,$8F659EFF,$F862AE69,$616BFFD3,$166CCF45,
    $A00AE278,$D70DD2EE,$4E048354,$3903B3C2,$A7672661,$D06016F7,$4969474D,$3E6E77DB,$AED16A4A,$D9D65ADC,$40DF0B66,$37D83BF0,$A9BCAE53,$DEBB9EC5,$47B2CF7F,$30B5FFE9,
    $BDBDF21C,$CABAC28A,$53B39330,$24B4A3A6,$BAD03605,$CDD70693,$54DE5729,$23D967BF,$B3667A2E,$C4614AB8,$5D681B02,$2A6F2B94,$B40BBE37,$C30C8EA1,$5A05DF1B,$2D02EF8D);
begin
var buffer:TBytes:=BytesOf(PathFilename);
CRC32:=$FFFFFFFF;
for var i:Integer:=0 to Length(buffer)-1 do
begin
    var PathNameChar:UInt32:=buffer;
    //额外处理西欧字符集问题
    if PathNameChar=$7E then PathNameChar:=$E9;
    if PathNameChar=$60 then PathNameChar:=$E7;
    //计算crc32
    CRC32:=(CRC32 shr 8) xor crc32CodeTable[(CRC32 xor PathNameChar) and $FF];
end;
end;

//控制台程序入口
begin
try
    //未提供命令行参数则显示帮助信息
    if ParamCount=0 then
    begin
      ShowHelp();
      Exit;
    end;

    //加载并解析参数配置文件
    var types:string:='';
    var sources:string:='';
    var targets:string:='';
    LoadConfigParam(types,sources,targets);
    if (types='')or(sources='')or(targets='') then
    begin
      Writeln('参数配置文件中的内容不正确或缺失,请重新指定。');
      Exit;
    end;

    //执行解包操作
    if types='unpackage' then
    begin
      //加载资源包文件(.TOC)
      var tocMemoryStream:TMemoryStream:=TMemoryStream.Create();
      if TFile.Exists(sources) then tocMemoryStream.LoadFromFile(sources);

      //资源包太小则不进行解包操作
      if tocMemoryStream.Size<160 then
      begin
      Writeln('在参数配置文件中由sources指定的资源包文件太小了,无法执行格式判断,请重新指定。');
      tocMemoryStream.Free();
      Exit;
      end;

      //检测PACK第一魔法值
      var pack:UInt32:=0;
      tocMemoryStream.ReadData(pack);
      if pack<>1262698832 then
      begin
      Writeln('在参数配置文件中由sources指定的文件不是资源包文件,请重新指定。');
      tocMemoryStream.Free();
      Exit;
      end;

      //检测REST第二魔法值
      var rest:UInt32:=0;
      tocMemoryStream.Position:=128;
      tocMemoryStream.ReadData(rest);
      if rest<>1414743378 then
      begin
      Writeln('在参数配置文件中由sources指定的文件不是资源包文件,请重新指定。');
      tocMemoryStream.Free();
      Exit;
      end;

      //检测文件表第一部分大小
      var fileTableSize:UInt32:=0;
      tocMemoryStream.Position:=136;
      tocMemoryStream.ReadData(fileTableSize);
      if (fileTableSize+160)>tocMemoryStream.Size then
      begin
      Writeln('资源包中的文件表第一部分大小不正确,无法进行解包操作。');
      tocMemoryStream.Free();
      Exit;
      end;

      //处理资源包关联文件
      var dirFilename:string:=TPath.GetDirectoryName(sources)+'\'+TPath.GetFileNameWithoutExtension(sources)+'.DIR';//文件表第二部分
      var datFilename:string:=TPath.GetDirectoryName(sources)+'\'+TPath.GetFileNameWithoutExtension(sources)+'.DAT';//文件数据
      if not TFile.Exists(dirFilename) then
      begin
      Writeln('指定的资源包缺少.DIR关联文件,无法进行解包操作。');
      tocMemoryStream.Free();
      Exit;
      end;
      if not TFile.Exists(datFilename) then
      begin
      Writeln('指定的资源包缺少.DAT关联文件,无法进行解包操作。');
      tocMemoryStream.Free();
      Exit;
      end;

      //初始化解包网格:【CRC32】【数据长度】【数据偏移】【文件名偏移】【文件名长度】【文件名】【存盘文件名】
      var fileCount:UInt32:=0;
      tocMemoryStream.ReadData(fileCount);
      var unpackageGrid:TStringGrid:=TStringGrid.Create(nil);
      unpackageGrid.RowCount:=fileCount;
      unpackageGrid.ColCount:=7;

      //解析文件表第一部分
      var buffer:UInt32:=0;
      tocMemoryStream.Position:=160;
      for var i:Integer:=0 to fileCount-1 do
      begin
      //获取crc32校验值
      tocMemoryStream.ReadData(buffer);
      unpackageGrid.Cells:=buffer.ToString();
      //获取文件数据长度(文件实际大小需要除以4)
      tocMemoryStream.ReadData(buffer);
      unpackageGrid.Cells:=(buffer div 4).ToString();
      //获取文件数据偏移
      tocMemoryStream.ReadData(buffer);
      unpackageGrid.Cells:=buffer.ToString();
      end;

      //解析文件表第二部分
      var dirMemoryStream:TMemoryStream:=TMemoryStream.Create();
      dirMemoryStream.LoadFromFile(dirFilename);
      var dirBuffer:TBytes;
      SetLength(dirBuffer,dirMemoryStream.Size);
      dirMemoryStream.ReadData(dirBuffer,dirMemoryStream.Size);
      //处理西欧字符集问题
      var filenameOffset:UInt32:=fileCount*4;
      for var i:Integer:=filenameOffset to Length(dirBuffer) do
      begin
      if dirBuffer=$E7 then dirBuffer:=$60;
      if dirBuffer=$E9 then dirBuffer:=$7E;
      end;
      dirMemoryStream.Clear();
      dirMemoryStream.WriteData(dirBuffer,Length(dirBuffer));
      dirMemoryStream.Position:=0;
      //获取文件名称偏移
      for var i:Integer:=0 to fileCount-1 do
      begin
      dirMemoryStream.ReadData(Buffer);
      unpackageGrid.Cells:=buffer.ToString();
      end;
      //计算文件名称长度
      for var i:UInt32:=0 to fileCount-1 do
      begin
      if i=(fileCount-1) then
      begin
          unpackageGrid.Cells:=(dirMemoryStream.Size-StrToUInt(unpackageGrid.Cells)).ToString();
      end else unpackageGrid.Cells:=(StrToUInt(unpackageGrid.Cells)-StrToUInt(unpackageGrid.Cells)).ToString();
      end;
      //获取文件名称
      var filename:TBytes;
      for var i:Integer:=0 to fileCount-1 do
      begin
      SetLength(filename,StrToUInt(unpackageGrid.Cells));
      dirMemoryStream.ReadData(filename,StrToUInt(unpackageGrid.Cells));
      unpackageGrid.Cells:=StringOf(filename);
      //获取存盘文件名称
      unpackageGrid.Cells:=TPath.GetFileNameWithoutExtension(sources)+'.smkb.'+GetFixString(i+1)+unpackageGrid.Cells.Replace('/','-smkb-');
      end;

      //解包存盘
      var datFileStream:TFileStream:=TFileStream.Create(datFilename,fmOpenRead);
      if targets<>'\' then targets:=targets+'\';//挂载路径后缀
      if not TDirectory.Exists(targets) then TDirectory.CreateDirectory(targets);//存盘文件夹不存在则创建
      var fileSaveStream:TMemoryStream:=TMemoryStream.Create();
      for var i:Integer:=0 to fileCount-1 do//循环解包存盘
      begin
      //解包资源文件
      Writeln((i+1).ToString()+'   '+targets+unpackageGrid.Cells);
      fileSaveStream.Clear();
      datFileStream.Position:=unpackageGrid.Cells.ToInt64();
      fileSaveStream.CopyFrom(datFileStream,StrToUInt(unpackageGrid.Cells));
      fileSaveStream.SaveToFile(targets+unpackageGrid.Cells);
      end;
      Writeln('解包操作完成,请在文件夹:'+targets+'下查看解包结果。');

      //完成解包操作后释放内存
      tocMemoryStream.Free();
      dirMemoryStream.Free();
      datFileStream.Free();
      unpackageGrid.Free();
      fileSaveStream.Free();
    end;

    //执行打包操作
    if types='package' then
    begin
      //挂载路径后缀
      if sources<>'\' then sources:=sources+'\';
      if targets<>'\' then targets:=targets+'\';

      //获取资源包名称
      var fileList:TStringDynArray:=TDirectory.GetFiles(sources,'*',TSearchOption.soTopDirectoryOnly);
      var assetNames:TStringList:=TStringList.Create();
      const splitString:string='.smkb.';
      for var i:Integer:=0 to Length(fileList)-1 do
      begin
      if assetNames.IndexOf(fileList.Replace(sources,'').Trim().Split(splitString).Trim())<0 then
      begin
          assetNames.Add(fileList.Replace(sources,'').Trim().Split(splitString).Trim());
      end;
      end;

      //初始化打包网格:【文件名】【crc32】【文件名长度】【文件名偏移】【数据长度】【数据偏移】
      var packageGrid:TStringGrid:=TStringGrid.Create(nil);
      packageGrid.ColCount:=6;

      //针对资源包名称分别打包
      var resourceMemoeyStream:TMemoryStream:=TMemoryStream.Create();
      for var i:Integer:=0 to assetNames.Count-1 do
      begin
      //获取当前资源文件列表
      fileList:=TDirectory.GetFiles(sources,assetNames.Strings+splitString+'*',TSearchOption.soTopDirectoryOnly);
      packageGrid.RowCount:=Length(fileList);

      //计算资源打包所需各项信息
      var filenameOffset:UInt32:=Length(fileList)*4;
      var fileDataOffset:UInt32:=0;
      for var j:Integer:=0 to Length(fileList)-1 do
      begin
          //加载资源文件
          resourceMemoeyStream.Clear();
          resourceMemoeyStream.LoadFromFile(fileList);

          //设置文件名
          packageGrid.Cells:=fileList.Replace(sources+assetNames.Strings+splitString,'').Replace('-smkb-','/').Substring(5).Trim();
          Writeln('正在计算打包资源信息,请耐心等待......'+packageGrid.Cells);

          //设置crc32
          var crc32:UInt32:=0;
          GetCRC32(packageGrid.Cells.Replace('/','|').Replace('\','|').ToLower(),crc32);
          packageGrid.Cells:=crc32.ToString();

          //设置文件名长度
          packageGrid.Cells:=(packageGrid.Cells.Length+1).ToString();

          //设置文件名偏移
          packageGrid.Cells:=filenameOffset.ToString();
          filenameOffset:=filenameOffset+StrToUInt(packageGrid.Cells);

          //设置数据大小
          packageGrid.Cells:=(resourceMemoeyStream.Size*4).ToString();

          //设置数据偏移
          packageGrid.Cells:=fileDataOffset.ToString();
          fileDataOffset:=fileDataOffset+resourceMemoeyStream.Size;
          var modValue:UInt32:=resourceMemoeyStream.Size mod 512;
          if modValue<>0 then fileDataOffset:=fileDataOffset+(512-modValue);
      end;

      //打包.TOC文件
      var tocMemoryStream:TMemoryStream:=TMemoryStream.Create();
      //写入文件头信息(共160字节)
      tocMemoryStream.WriteData(BytesOf('PACK'),4);
      tocMemoryStream.WriteData(65536,4);
      tocMemoryStream.WriteData(96,4);
      tocMemoryStream.WriteData(3,4);
      for var j:Integer:=1 to 16 do tocMemoryStream.WriteData($00,1);
      tocMemoryStream.WriteData(BytesOf('MKRT'),4);
      tocMemoryStream.WriteData(65536,4);
      for var j:Integer:=1 to 24 do tocMemoryStream.WriteData($00,1);
      tocMemoryStream.WriteData(BytesOf('OFFT'),4);
      tocMemoryStream.WriteData(65536,4);
      for var j:Integer:=1 to 24 do tocMemoryStream.WriteData($00,1);
      tocMemoryStream.WriteData(BytesOf('DEPT'),4);
      tocMemoryStream.WriteData(65536,4);
      for var j:Integer:=1 to 24 do tocMemoryStream.WriteData($00,1);
      tocMemoryStream.WriteData(BytesOf('REST'),4);
      tocMemoryStream.WriteData(65536,4);
      tocMemoryStream.WriteData(packageGrid.RowCount*12,4);
      tocMemoryStream.WriteData(packageGrid.RowCount,4);
      for var j:Integer:=1 to 16 do tocMemoryStream.WriteData($00,1);
      //写入文件表第一部分信息(每个文件12字节)
      for var j:Integer:=0 to Length(fileList)-1 do
      begin
          tocMemoryStream.WriteData(StrToUInt(packageGrid.Cells),4);
          tocMemoryStream.WriteData(StrToUInt(packageGrid.Cells),4);
          tocMemoryStream.WriteData(StrToUInt(packageGrid.Cells),4);
      end;
      tocMemoryStream.SaveToFile(targets+assetNames.Strings+'.TOC');
      tocMemoryStream.Free();

      //打包.DIR文件
      var dirMemoryStream:TMemoryStream:=TMemoryStream.Create();
      //写入文件表第二部分信息(文件名称偏移信息)
      for var j:Integer:=0 to Length(fileList)-1 do dirMemoryStream.WriteData(StrToUInt(packageGrid.Cells),4);
      //写入文件表第二部分信息(文件名称信息)
      var filenameBuffer:TBytes;
      for var j:Integer:=0 to Length(fileList)-1 do
      begin
          SetLength(filenameBuffer,packageGrid.Cells.Length);
          filenameBuffer:=BytesOf(packageGrid.Cells);
          //处理西欧字符集问题
          for var k:Integer:=0 to Length(filenameBuffer)-1 do
          begin
            if filenameBuffer=$7E then filenameBuffer:=$E9;
            if filenameBuffer=$60 then filenameBuffer:=$E7;
          end;
          dirMemoryStream.WriteData(filenameBuffer,Length(filenameBuffer));
          dirMemoryStream.WriteData($00,1);
      end;
      dirMemoryStream.SaveToFile(targets+assetNames.Strings+'.DIR');
      dirMemoryStream.Free();

      //打包.DAT文件
      var datFileStream:TFileStream:=TFileStream.Create(targets+assetNames.Strings+'.DAT',fmCreate);
      var fileDataBuffer:TBytes;
      for var j:Integer:=0 to Length(fileList)-1 do
      begin
          //加载资源文件
          resourceMemoeyStream.Clear();
          resourceMemoeyStream.LoadFromFile(fileList);
          Writeln((j+1).ToString()+'   '+fileList);
          SetLength(fileDataBuffer,resourceMemoeyStream.Size);
          resourceMemoeyStream.ReadData(fileDataBuffer,resourceMemoeyStream.Size);
          //写入数据文件信息(需要512字节对齐)
          datFileStream.WriteData(fileDataBuffer,resourceMemoeyStream.Size);
          if (resourceMemoeyStream.Size mod 512)<>0 then for var k:Integer:=1 to 512-(resourceMemoeyStream.Size mod 512) do datFileStream.WriteData($00,1);
      end;
      datFileStream.Free();
      end;
      Writeln('打包操作完成,请在文件夹:'+targets+'下查看打包结果。');

      //完成打包操作后释放内存
      assetNames.Free();
      packageGrid.Free();
      resourceMemoeyStream.Free();
    end;

    //执行汉化补丁打包操作
    if types='patch' then
    begin
      //挂载路径后缀
      if sources<>'\' then sources:=sources+'\';
      if targets<>'\' then targets:=targets+'\';

      //获取资源包名称
      var fileList:TStringDynArray:=TDirectory.GetFiles(sources,'*',TSearchOption.soTopDirectoryOnly);
      var assetNames:TStringList:=TStringList.Create();
      const splitString:string='.smkb.';
      for var i:Integer:=0 to Length(fileList)-1 do
      begin
      if assetNames.IndexOf(fileList.Replace(sources,'').Trim().Split(splitString).Trim())<0 then
      begin
          assetNames.Add(fileList.Replace(sources,'').Trim().Split(splitString).Trim());
      end;
      end;

      //初始化汉化补丁打包网格:【文件名】【crc32】【文件名长度】【文件名偏移】【数据长度】【数据偏移】
      var patchGrid:TStringGrid:=TStringGrid.Create(nil);
      patchGrid.ColCount:=6;
      patchGrid.RowCount:=Length(fileList);

      //计算资源打包所需各项信息
      var filenameOffset:UInt32:=Length(fileList)*4;
      var fileDataOffset:UInt32:=0;
      var resourceMemoeyStream:TMemoryStream:=TMemoryStream.Create();
      for var j:Integer:=0 to Length(fileList)-1 do
      begin
      //加载资源文件
      resourceMemoeyStream.Clear();
      resourceMemoeyStream.LoadFromFile(fileList);

      //设置文件名
      patchGrid.Cells:=fileList;
      for var i:Integer:=0 to assetNames.Count-1 do patchGrid.Cells:=patchGrid.Cells.Replace(sources+assetNames.Strings+splitString,'');
      patchGrid.Cells:=patchGrid.Cells.Replace('-smkb-','/').Substring(5).Trim();
      Writeln('正在计算打包资源信息,请耐心等待......'+patchGrid.Cells);

      //设置crc32
      var crc32:UInt32:=0;
      GetCRC32(patchGrid.Cells.Replace('/','|').Replace('\','|').ToLower(),crc32);
      patchGrid.Cells:=crc32.ToString();

      //设置文件名长度
      patchGrid.Cells:=(patchGrid.Cells.Length+1).ToString();

      //设置文件名偏移
      patchGrid.Cells:=filenameOffset.ToString();
      filenameOffset:=filenameOffset+StrToUInt(patchGrid.Cells);

      //设置数据大小
      patchGrid.Cells:=(resourceMemoeyStream.Size*4).ToString();

      //设置数据偏移
      patchGrid.Cells:=fileDataOffset.ToString();
      fileDataOffset:=fileDataOffset+resourceMemoeyStream.Size;
      var modValue:UInt32:=resourceMemoeyStream.Size mod 512;
      if modValue<>0 then fileDataOffset:=fileDataOffset+(512-modValue);
      end;

      //打包.TOC文件
      var tocMemoryStream:TMemoryStream:=TMemoryStream.Create();
      //写入文件头信息(共160字节)
      tocMemoryStream.WriteData(BytesOf('PACK'),4);
      tocMemoryStream.WriteData(65536,4);
      tocMemoryStream.WriteData(96,4);
      tocMemoryStream.WriteData(3,4);
      for var j:Integer:=1 to 16 do tocMemoryStream.WriteData($00,1);
      tocMemoryStream.WriteData(BytesOf('MKRT'),4);
      tocMemoryStream.WriteData(65536,4);
      for var j:Integer:=1 to 24 do tocMemoryStream.WriteData($00,1);
      tocMemoryStream.WriteData(BytesOf('OFFT'),4);
      tocMemoryStream.WriteData(65536,4);
      for var j:Integer:=1 to 24 do tocMemoryStream.WriteData($00,1);
      tocMemoryStream.WriteData(BytesOf('DEPT'),4);
      tocMemoryStream.WriteData(65536,4);
      for var j:Integer:=1 to 24 do tocMemoryStream.WriteData($00,1);
      tocMemoryStream.WriteData(BytesOf('REST'),4);
      tocMemoryStream.WriteData(65536,4);
      tocMemoryStream.WriteData(patchGrid.RowCount*12,4);
      tocMemoryStream.WriteData(patchGrid.RowCount,4);
      for var j:Integer:=1 to 16 do tocMemoryStream.WriteData($00,1);
      //写入文件表第一部分信息(每个文件12字节)
      for var j:Integer:=0 to Length(fileList)-1 do
      begin
      tocMemoryStream.WriteData(StrToUInt(patchGrid.Cells),4);
      tocMemoryStream.WriteData(StrToUInt(patchGrid.Cells),4);
      tocMemoryStream.WriteData(StrToUInt(patchGrid.Cells),4);
      end;
      tocMemoryStream.SaveToFile(targets+'PATCH.TOC');
      tocMemoryStream.Free();

      //打包.DIR文件
      var dirMemoryStream:TMemoryStream:=TMemoryStream.Create();
      //写入文件表第二部分信息(文件名称偏移信息)
      for var j:Integer:=0 to Length(fileList)-1 do dirMemoryStream.WriteData(StrToUInt(patchGrid.Cells),4);
      //写入文件表第二部分信息(文件名称信息)
      var filenameBuffer:TBytes;
      for var j:Integer:=0 to Length(fileList)-1 do
      begin
      SetLength(filenameBuffer,patchGrid.Cells.Length);
      filenameBuffer:=BytesOf(patchGrid.Cells);
      //处理西欧字符集问题
      for var k:Integer:=0 to Length(filenameBuffer)-1 do
      begin
          if filenameBuffer=$7E then filenameBuffer:=$E9;
          if filenameBuffer=$60 then filenameBuffer:=$E7;
      end;
      dirMemoryStream.WriteData(filenameBuffer,Length(filenameBuffer));
      dirMemoryStream.WriteData($00,1);
      end;
      dirMemoryStream.SaveToFile(targets+'PATCH.DIR');
      dirMemoryStream.Free();

      //打包.DAT文件
      var datFileStream:TFileStream:=TFileStream.Create(targets+'PATCH.DAT',fmCreate);
      var fileDataBuffer:TBytes;
      for var j:Integer:=0 to Length(fileList)-1 do
      begin
      //加载资源文件
      resourceMemoeyStream.Clear();
      resourceMemoeyStream.LoadFromFile(fileList);
      Writeln((j+1).ToString()+'   '+fileList);
      SetLength(fileDataBuffer,resourceMemoeyStream.Size);
      resourceMemoeyStream.ReadData(fileDataBuffer,resourceMemoeyStream.Size);
      //写入数据文件信息(需要512字节对齐)
      datFileStream.WriteData(fileDataBuffer,resourceMemoeyStream.Size);
      if (resourceMemoeyStream.Size mod 512)<>0 then for var k:Integer:=1 to 512-(resourceMemoeyStream.Size mod 512) do datFileStream.WriteData($00,1);
      end;
      datFileStream.Free();

      //生成资源配置文件(需要放在游戏执行文件同一目录)
      var resourceConfig:TResourceStream:=TResourceStream.Create(HInstance,'patch',RT_RCDATA);
      resourceConfig.SaveToFile(targets+'resources.cfg');
      resourceConfig.Free();

      Writeln('汉化补丁打包操作完成,请在文件夹:'+targets+'下查看汉化补丁打包结果。');

      //完成打包操作后释放内存
      assetNames.Free();
      patchGrid.Free();
      resourceMemoeyStream.Free();
    end;
except
    on E: Exception do
    begin
      Writeln(E.ClassName, ': ', E.Message);
    end;
end;
end.


chz268 发表于 2020-12-22 09:35

{:1_921:}{:1_921:}{:1_921:}{:1_921:}{:1_921:}厉害哦。

夏天爸爸 发表于 2020-12-22 09:46

人才济济,收藏起来

asong 发表于 2021-1-21 10:46

delphi资料奇缺,感谢分享。
页: [1]
查看完整版本: OGRE资源管理器源代码