Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- (* Converts between DoomRL.wad format and cpio -H newc format *)
- uses zstream, idea, getopts, Classes, sysutils;
- type
- TVDFClumpFlags = set of (vdfCompressed,vdfEncrypted);
- TVDFHeader = packed record
- Signature : string[8];
- Version : DWord;
- Files : DWord;
- end;
- TVDFClumpHeader = packed record
- Size : DWord;
- Pos : DWord;
- Dir : string[64];
- Name : string[64];
- Flags : TVDFClumpFlags;
- FType : DWord;
- end;
- TCPIOHeader = packed record
- Magic : Array [1..6] of Char;
- Ino : Array [1..8] of Char;
- Mode : Array [1..8] of Char;
- UID : Array [1..8] of Char;
- GID : Array [1..8] of Char;
- NLink : Array [1..8] of Char;
- ModTime : Array [1..8] of Char;
- FileSize : Array [1..8] of Char;
- DevMajor : Array [1..8] of Char;
- DevMinor : Array [1..8] of Char;
- RDevMajr : Array [1..8] of Char;
- RDevMinr : Array [1..8] of Char;
- NameSize : Array [1..8] of Char;
- Check : Array [1..8] of Char;
- end;
- var
- CryptKey : TIDEAKey;
- CryptKeySet : Boolean = False;
- Compress : Boolean = False;
- procedure Encode;
- var
- MainHeader : TVDFHeader;
- FileHeaders : Array of TVDFClumpHeader;
- RawWriter : TMemoryStream;
- Encryptor : TIDEAEncryptStream;
- Compressor : TCompressionStream;
- Out : TStream;
- CPIOFile : File;
- CPIOHeader : TCPIOHeader;
- OutFile : File;
- Field : ShortString;
- FileMode, FileSize, NameSize : Integer;
- Data : Array of Char;
- ValCode, ValCode2 : Word;
- FType : Integer;
- FileName : AnsiString;
- FNum : Integer;
- begin
- MainHeader.Signature := 'VDFILE01';
- MainHeader.Version := 0;
- MainHeader.Files := 0;
- Assign(CPIOFile, '');
- Reset(CPIOFile, 1);
- RawWriter := TMemoryStream.Create;
- while not Eof(CPIOFile) do
- begin
- Blockread(CPIOFile, CPIOHeader, Sizeof(CPIOHeader));
- SetString(Field, @CPIOHeader.Magic[1], 6);
- if (Field <> '070701') and (Field <> '070702') then
- begin
- Writeln(StdErr, 'Signature error in CPIO input data');
- Halt;
- end;
- SetString(Field, @CPIOHeader.Mode[1], 8);
- Val('$' + Field, FileMode, ValCode);
- SetString(Field, @CPIOHeader.FileSize[1], 8);
- Val('$' + Field, FileSize, ValCode);
- SetString(Field, @CPIOHeader.NameSize[1], 8);
- Val('$' + Field, NameSize, ValCode);
- SetLength(Data, ((NameSize + 5) and not 3) - 2);
- Blockread(CPIOFile, Data[0], ((NameSize + 5) and not 3) - 2);
- SetString(FileName, @Data[0], NameSize-1); (* trailing NUL *)
- SetLength(Data, (FileSize + 3) and not 3);
- Blockread(CPIOFile, Data[0], (FileSize + 3) and not 3);
- (* Don't save directories - this isn't working
- if (FileMode and $0F000) = $04000 then Continue;
- if (FileMode and (15*4096)) <> 32768 then
- begin
- Writeln(StdErr, 'Weird file of type $' + HexStr(FileMode and (15*4096), 8) + ' found in archive');
- Halt;
- end; *)
- if FileName = 'TRAILER!!!' then Continue;
- Val(FileName, FType, ValCode);
- if ValCode = 0 then
- FType := 0
- else
- begin
- Val(LeftStr(FileName, ValCode-1), FType, ValCode2);
- FileName := RightStr(FileName, Length(FileName)-(ValCode-1));
- end;
- Inc(MainHeader.Files);
- SetLength(FileHeaders, MainHeader.Files);
- FileHeaders[MainHeader.Files - 1].Pos := RawWriter.Position;
- FileHeaders[MainHeader.Files - 1].Size := FileSize;
- FileHeaders[MainHeader.Files - 1].Dir := ''; (* XXX should be part of the filename *)
- FileHeaders[MainHeader.Files - 1].Name := FileName;
- FileHeaders[MainHeader.Files - 1].Flags := [];
- FileHeaders[MainHeader.Files - 1].FType := FType;
- Out := RawWriter;
- if CryptKeySet then
- begin
- Encryptor := TIDEAEncryptStream.Create(CryptKey, Out);
- Out := Encryptor;
- Include(FileHeaders[MainHeader.Files - 1].Flags, vdfEncrypted);
- end;
- if Compress then
- begin
- Compressor := TCompressionStream.Create(clmax, Out);
- Out := Compressor;
- Include(FileHeaders[MainHeader.Files - 1].Flags, vdfCompressed);
- end;
- Out.WriteBuffer(Data[0], FileSize);
- Out := Nil;
- FreeAndNil(Compressor);
- FreeAndNil(Encryptor);
- end;
- for FNum := 0 to High(FileHeaders) do
- FileHeaders[FNum].Pos := FileHeaders[FNum].Pos + SizeOf(MainHeader) + SizeOf(FileHeaders[0]) * MainHeader.Files;
- Assign(OutFile, '');
- Rewrite(OutFile, 1);
- Blockwrite(OutFile, MainHeader, SizeOf(MainHeader));
- for FNum := 0 to High(FileHeaders) do
- Blockwrite(OutFile, FileHeaders[FNum], SizeOf(FileHeaders[FNum]));
- Blockwrite(OutFile, RawWriter.Memory^, RawWriter.Position);
- FreeAndNil(RawWriter);
- end;
- procedure Decode;
- var
- MainHeader : TVDFHeader;
- FileHeaders : Array of TVDFClumpHeader;
- RawReader : TMemoryStream;
- Decryptor : TIDEADeCryptStream;
- Decompressor : TDecompressionStream;
- InStr : TStream;
- FNum : Integer;
- Data : Array of Char;
- MangledName : AnsiString;
- N : Integer;
- CPIOHeader : String;
- Out : File;
- InFile : File;
- begin
- RawReader := TMemoryStream.Create;
- Assign(InFile, '');
- Reset(InFile, 1);
- SetLength(Data, 4096);
- while True do
- begin
- Blockread(InFile, Data[0], 4096, N);
- if N = 0 then Break;
- RawReader.WriteBuffer(Data[0], N);
- end;
- RawReader.Position := 0;
- RawReader.ReadBuffer(MainHeader, SizeOf(MainHeader));
- Assign(Out, '');
- Rewrite(Out, 1);
- SetLength(FileHeaders, MainHeader.Files);
- RawReader.ReadBuffer(FileHeaders[0], SizeOf(FileHeaders[0]) * MainHeader.Files);
- for FNum := 0 to High(FileHeaders) do
- begin
- RawReader.Position := FileHeaders[FNum].Pos;
- InStr := RawReader;
- if vdfEncrypted in FileHeaders[FNum].Flags then
- begin
- if not CryptKeySet then
- begin
- Writeln(StdErr, 'Encrypted file encountered, but you did not provide a key!');
- Halt;
- end;
- Decryptor := TIDEADeCryptStream.Create(CryptKey, InStr);
- InStr := Decryptor;
- end;
- if vdfCompressed in FileHeaders[FNum].Flags then
- begin
- Decompressor := TDecompressionStream.Create(InStr);
- InStr := Decompressor;
- end;
- SetLength(Data, FileHeaders[FNum].Size);
- InStr.ReadBuffer(Data[0], FileHeaders[FNum].Size);
- FreeAndNil(Decompressor);
- FreeAndNil(Decryptor);
- InStr := Nil;
- MangledName := '';
- if FileHeaders[FNum].Dir <> '' then
- MangledName := FileHeaders[FNum].Dir + '/';
- MangledName := MangledName + IntToStr(FileHeaders[FNum].FType) + FileHeaders[FNum].Name + #0;
- CPIOHeader := '070701' + HexStr(FNum, 8) + '000081A4' + '00000000' + '00000000' + '00000001' + '00000000' + HexStr(FileHeaders[FNum].Size, 8) + '00000000' + '00000000' + '00000000' + '00000000' + HexStr(Length(MangledName), 8) + '00000000';
- Blockwrite(Out, CPIOHeader[1], Length(CPIOHeader));
- Blockwrite(Out, MangledName[1], Length(MangledName));
- for N := 1 to (2-Length(MangledName)) and 3 do
- Blockwrite(Out, 0, 1);
- Blockwrite(Out, Data[0], FileHeaders[FNum].Size);
- for N := 1 to (-FileHeaders[FNum].Size) and 3 do
- Blockwrite(Out, 0, 1);
- end;
- CPIOHeader := '070701FFFFFFFF000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!' + #0 + #0 + #0 + #0;
- Blockwrite(Out, CPIOHeader[1], Length(CPIOHeader));
- end;
- procedure SetKeyFile(Name : String);
- var
- F : File;
- begin
- Assign(F, Name);
- Reset(F, 1);
- Blockread(F, CryptKey, SizeOf(CryptKey));
- CryptKeySet := True;
- end;
- var
- Mode : String = '';
- begin
- Filemode := 0;
- while True do
- begin
- case GetOpt('edzk:') of
- 'e':
- Mode := Mode + 'e';
- 'd':
- Mode := Mode + 'd';
- 'z':
- Compress := True;
- 'k':
- SetKeyFile(OptArg);
- '?':
- Mode := Mode + '?';
- EndOfOptions:
- Break;
- end;
- end;
- if Mode = 'e' then Encode
- else if Mode = 'd' then Decode
- else begin
- Writeln(StdErr, 'Converts between valkyrie data files like doomrl.wad and standard CPIO archives.');
- Writeln(StdErr, '');
- Writeln(StdErr, 'Usage: vdftool [-k keyfile] -d < doomrl.wad > doomrl.cpio');
- Writeln(StdErr, ' vdftool [-k keyfile] [-z] < doomrl.cpio > doomrl.wad');
- end;
- end.
Add Comment
Please, Sign In to add comment