Guest User

Untitled

a guest
Jul 21st, 2018
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.94 KB | None | 0 0
  1. (* Converts between DoomRL.wad format and cpio -H newc format *)
  2.  
  3. uses zstream, idea, getopts, Classes, sysutils;
  4.  
  5. type
  6. TVDFClumpFlags = set of (vdfCompressed,vdfEncrypted);
  7.  
  8. TVDFHeader = packed record
  9. Signature : string[8];
  10. Version : DWord;
  11. Files : DWord;
  12. end;
  13.  
  14. TVDFClumpHeader = packed record
  15. Size : DWord;
  16. Pos : DWord;
  17. Dir : string[64];
  18. Name : string[64];
  19. Flags : TVDFClumpFlags;
  20. FType : DWord;
  21. end;
  22.  
  23. TCPIOHeader = packed record
  24. Magic : Array [1..6] of Char;
  25. Ino : Array [1..8] of Char;
  26. Mode : Array [1..8] of Char;
  27. UID : Array [1..8] of Char;
  28. GID : Array [1..8] of Char;
  29. NLink : Array [1..8] of Char;
  30. ModTime : Array [1..8] of Char;
  31. FileSize : Array [1..8] of Char;
  32. DevMajor : Array [1..8] of Char;
  33. DevMinor : Array [1..8] of Char;
  34. RDevMajr : Array [1..8] of Char;
  35. RDevMinr : Array [1..8] of Char;
  36. NameSize : Array [1..8] of Char;
  37. Check : Array [1..8] of Char;
  38. end;
  39.  
  40. var
  41. CryptKey : TIDEAKey;
  42. CryptKeySet : Boolean = False;
  43. Compress : Boolean = False;
  44.  
  45. procedure Encode;
  46. var
  47. MainHeader : TVDFHeader;
  48. FileHeaders : Array of TVDFClumpHeader;
  49. RawWriter : TMemoryStream;
  50. Encryptor : TIDEAEncryptStream;
  51. Compressor : TCompressionStream;
  52. Out : TStream;
  53. CPIOFile : File;
  54. CPIOHeader : TCPIOHeader;
  55. OutFile : File;
  56. Field : ShortString;
  57. FileMode, FileSize, NameSize : Integer;
  58. Data : Array of Char;
  59. ValCode, ValCode2 : Word;
  60. FType : Integer;
  61. FileName : AnsiString;
  62. FNum : Integer;
  63. begin
  64. MainHeader.Signature := 'VDFILE01';
  65. MainHeader.Version := 0;
  66. MainHeader.Files := 0;
  67.  
  68. Assign(CPIOFile, '');
  69. Reset(CPIOFile, 1);
  70.  
  71. RawWriter := TMemoryStream.Create;
  72.  
  73. while not Eof(CPIOFile) do
  74. begin
  75. Blockread(CPIOFile, CPIOHeader, Sizeof(CPIOHeader));
  76.  
  77. SetString(Field, @CPIOHeader.Magic[1], 6);
  78. if (Field <> '070701') and (Field <> '070702') then
  79. begin
  80. Writeln(StdErr, 'Signature error in CPIO input data');
  81. Halt;
  82. end;
  83.  
  84. SetString(Field, @CPIOHeader.Mode[1], 8);
  85. Val('$' + Field, FileMode, ValCode);
  86.  
  87. SetString(Field, @CPIOHeader.FileSize[1], 8);
  88. Val('$' + Field, FileSize, ValCode);
  89.  
  90. SetString(Field, @CPIOHeader.NameSize[1], 8);
  91. Val('$' + Field, NameSize, ValCode);
  92.  
  93. SetLength(Data, ((NameSize + 5) and not 3) - 2);
  94. Blockread(CPIOFile, Data[0], ((NameSize + 5) and not 3) - 2);
  95.  
  96. SetString(FileName, @Data[0], NameSize-1); (* trailing NUL *)
  97.  
  98. SetLength(Data, (FileSize + 3) and not 3);
  99. Blockread(CPIOFile, Data[0], (FileSize + 3) and not 3);
  100.  
  101. (* Don't save directories - this isn't working
  102. if (FileMode and $0F000) = $04000 then Continue;
  103.  
  104. if (FileMode and (15*4096)) <> 32768 then
  105. begin
  106. Writeln(StdErr, 'Weird file of type $' + HexStr(FileMode and (15*4096), 8) + ' found in archive');
  107. Halt;
  108. end; *)
  109.  
  110. if FileName = 'TRAILER!!!' then Continue;
  111.  
  112. Val(FileName, FType, ValCode);
  113. if ValCode = 0 then
  114. FType := 0
  115. else
  116. begin
  117. Val(LeftStr(FileName, ValCode-1), FType, ValCode2);
  118. FileName := RightStr(FileName, Length(FileName)-(ValCode-1));
  119. end;
  120.  
  121. Inc(MainHeader.Files);
  122. SetLength(FileHeaders, MainHeader.Files);
  123.  
  124. FileHeaders[MainHeader.Files - 1].Pos := RawWriter.Position;
  125. FileHeaders[MainHeader.Files - 1].Size := FileSize;
  126. FileHeaders[MainHeader.Files - 1].Dir := ''; (* XXX should be part of the filename *)
  127. FileHeaders[MainHeader.Files - 1].Name := FileName;
  128. FileHeaders[MainHeader.Files - 1].Flags := [];
  129. FileHeaders[MainHeader.Files - 1].FType := FType;
  130.  
  131. Out := RawWriter;
  132.  
  133. if CryptKeySet then
  134. begin
  135. Encryptor := TIDEAEncryptStream.Create(CryptKey, Out);
  136. Out := Encryptor;
  137. Include(FileHeaders[MainHeader.Files - 1].Flags, vdfEncrypted);
  138. end;
  139.  
  140. if Compress then
  141. begin
  142. Compressor := TCompressionStream.Create(clmax, Out);
  143. Out := Compressor;
  144. Include(FileHeaders[MainHeader.Files - 1].Flags, vdfCompressed);
  145. end;
  146.  
  147. Out.WriteBuffer(Data[0], FileSize);
  148.  
  149. Out := Nil;
  150. FreeAndNil(Compressor);
  151. FreeAndNil(Encryptor);
  152. end;
  153.  
  154. for FNum := 0 to High(FileHeaders) do
  155. FileHeaders[FNum].Pos := FileHeaders[FNum].Pos + SizeOf(MainHeader) + SizeOf(FileHeaders[0]) * MainHeader.Files;
  156.  
  157. Assign(OutFile, '');
  158. Rewrite(OutFile, 1);
  159.  
  160. Blockwrite(OutFile, MainHeader, SizeOf(MainHeader));
  161.  
  162. for FNum := 0 to High(FileHeaders) do
  163. Blockwrite(OutFile, FileHeaders[FNum], SizeOf(FileHeaders[FNum]));
  164.  
  165. Blockwrite(OutFile, RawWriter.Memory^, RawWriter.Position);
  166.  
  167. FreeAndNil(RawWriter);
  168. end;
  169.  
  170. procedure Decode;
  171. var
  172. MainHeader : TVDFHeader;
  173. FileHeaders : Array of TVDFClumpHeader;
  174. RawReader : TMemoryStream;
  175. Decryptor : TIDEADeCryptStream;
  176. Decompressor : TDecompressionStream;
  177. InStr : TStream;
  178. FNum : Integer;
  179. Data : Array of Char;
  180. MangledName : AnsiString;
  181. N : Integer;
  182. CPIOHeader : String;
  183. Out : File;
  184. InFile : File;
  185. begin
  186. RawReader := TMemoryStream.Create;
  187.  
  188. Assign(InFile, '');
  189. Reset(InFile, 1);
  190.  
  191. SetLength(Data, 4096);
  192. while True do
  193. begin
  194. Blockread(InFile, Data[0], 4096, N);
  195. if N = 0 then Break;
  196. RawReader.WriteBuffer(Data[0], N);
  197. end;
  198.  
  199. RawReader.Position := 0;
  200. RawReader.ReadBuffer(MainHeader, SizeOf(MainHeader));
  201.  
  202. Assign(Out, '');
  203. Rewrite(Out, 1);
  204.  
  205. SetLength(FileHeaders, MainHeader.Files);
  206.  
  207. RawReader.ReadBuffer(FileHeaders[0], SizeOf(FileHeaders[0]) * MainHeader.Files);
  208.  
  209. for FNum := 0 to High(FileHeaders) do
  210. begin
  211. RawReader.Position := FileHeaders[FNum].Pos;
  212. InStr := RawReader;
  213.  
  214. if vdfEncrypted in FileHeaders[FNum].Flags then
  215. begin
  216. if not CryptKeySet then
  217. begin
  218. Writeln(StdErr, 'Encrypted file encountered, but you did not provide a key!');
  219. Halt;
  220. end;
  221.  
  222. Decryptor := TIDEADeCryptStream.Create(CryptKey, InStr);
  223. InStr := Decryptor;
  224. end;
  225.  
  226. if vdfCompressed in FileHeaders[FNum].Flags then
  227. begin
  228. Decompressor := TDecompressionStream.Create(InStr);
  229. InStr := Decompressor;
  230. end;
  231.  
  232. SetLength(Data, FileHeaders[FNum].Size);
  233. InStr.ReadBuffer(Data[0], FileHeaders[FNum].Size);
  234.  
  235. FreeAndNil(Decompressor);
  236. FreeAndNil(Decryptor);
  237.  
  238. InStr := Nil;
  239.  
  240. MangledName := '';
  241.  
  242. if FileHeaders[FNum].Dir <> '' then
  243. MangledName := FileHeaders[FNum].Dir + '/';
  244.  
  245. MangledName := MangledName + IntToStr(FileHeaders[FNum].FType) + FileHeaders[FNum].Name + #0;
  246.  
  247. CPIOHeader := '070701' + HexStr(FNum, 8) + '000081A4' + '00000000' + '00000000' + '00000001' + '00000000' + HexStr(FileHeaders[FNum].Size, 8) + '00000000' + '00000000' + '00000000' + '00000000' + HexStr(Length(MangledName), 8) + '00000000';
  248.  
  249. Blockwrite(Out, CPIOHeader[1], Length(CPIOHeader));
  250.  
  251. Blockwrite(Out, MangledName[1], Length(MangledName));
  252.  
  253. for N := 1 to (2-Length(MangledName)) and 3 do
  254. Blockwrite(Out, 0, 1);
  255.  
  256. Blockwrite(Out, Data[0], FileHeaders[FNum].Size);
  257.  
  258. for N := 1 to (-FileHeaders[FNum].Size) and 3 do
  259. Blockwrite(Out, 0, 1);
  260. end;
  261.  
  262. CPIOHeader := '070701FFFFFFFF000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!' + #0 + #0 + #0 + #0;
  263. Blockwrite(Out, CPIOHeader[1], Length(CPIOHeader));
  264. end;
  265.  
  266. procedure SetKeyFile(Name : String);
  267. var
  268. F : File;
  269. begin
  270. Assign(F, Name);
  271. Reset(F, 1);
  272.  
  273. Blockread(F, CryptKey, SizeOf(CryptKey));
  274. CryptKeySet := True;
  275. end;
  276.  
  277. var
  278. Mode : String = '';
  279. begin
  280. Filemode := 0;
  281. while True do
  282. begin
  283. case GetOpt('edzk:') of
  284. 'e':
  285. Mode := Mode + 'e';
  286. 'd':
  287. Mode := Mode + 'd';
  288. 'z':
  289. Compress := True;
  290. 'k':
  291. SetKeyFile(OptArg);
  292. '?':
  293. Mode := Mode + '?';
  294. EndOfOptions:
  295. Break;
  296. end;
  297. end;
  298.  
  299. if Mode = 'e' then Encode
  300. else if Mode = 'd' then Decode
  301. else begin
  302. Writeln(StdErr, 'Converts between valkyrie data files like doomrl.wad and standard CPIO archives.');
  303. Writeln(StdErr, '');
  304. Writeln(StdErr, 'Usage: vdftool [-k keyfile] -d < doomrl.wad > doomrl.cpio');
  305. Writeln(StdErr, ' vdftool [-k keyfile] [-z] < doomrl.cpio > doomrl.wad');
  306. end;
  307. end.
Add Comment
Please, Sign In to add comment