1 (* Copyright (C) Doom 2D: Forever Developers
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // simple grouping files w/o packing:
17 // Quake I/II .PAK (PACK)
20 {$INCLUDE ../shared/a_modes.inc}
28 SysUtils
, Classes
, Contnrs
, sfs
;
32 TSFSPlainVolumeType
= (sfspvNone
, sfspvPAK
, sfspvSIN
);
34 TSFSPlainVolume
= class (TSFSVolume
)
36 fType
: TSFSPlainVolumeType
;
38 procedure ReadDirectory (); override;
41 function OpenFileByIndex (const index
: Integer): TStream
; override;
44 TSFSPlainVolumeFactory
= class (TSFSVolumeFactory
)
46 function IsMyVolumePrefix (const prefix
: AnsiString): Boolean; override;
47 function Produce (const prefix
, fileName
: AnsiString; st
: TStream
): TSFSVolume
; override;
48 procedure Recycle (vol
: TSFSVolume
); override;
59 procedure TSFSPlainVolume
.ReadDirectory ();
61 dsize
, dofs
, esz
: LongWord;
63 name
: packed array [0..120] of Char;
65 if (fType
<> sfspvPAK
) and (fType
<> sfspvSIN
) then raise ESFSError
.Create('invalid archive');
66 fFileStream
.Seek(4, soCurrent
); // skip signature
67 dofs
:= readLongWord(fFileStream
);
68 dsize
:= readLongWord(fFileStream
);
69 fFileStream
.Position
:= dofs
;
70 if fType
= sfspvPAK
then esz
:= 64 else esz
:= 128;
73 fi
:= TSFSFileInfo
.Create(self
);
74 FillChar(name
[0], length(name
), 0);
75 fFileStream
.ReadBuffer(name
[0], esz
-8);
76 fi
.fName
:= PChar(@name
[0]);
77 fi
.fOfs
:= readLongWord(fFileStream
);
78 fi
.fSize
:= readLongWord(fFileStream
);
83 function TSFSPlainVolume
.OpenFileByIndex (const index
: Integer): TStream
;
86 if fFiles
= nil then exit
;
87 if (index
< 0) or (index
>= fFiles
.Count
) or (fFiles
[index
] = nil) then exit
;
88 result
:= TSFSPartialStream
.Create(fFileStream
, TSFSFileInfo(fFiles
[index
]).fOfs
, TSFSFileInfo(fFiles
[index
]).fSize
, false);
92 { TSFSPlainVolumeFactory }
93 function TSFSPlainVolumeFactory
.IsMyVolumePrefix (const prefix
: AnsiString): Boolean;
96 StrEquCI1251(prefix
, 'pak') or
97 StrEquCI1251(prefix
, 'sin');
100 procedure TSFSPlainVolumeFactory
.Recycle (vol
: TSFSVolume
);
105 function TSFSPlainVolumeFactory
.Produce (const prefix
, fileName
: AnsiString; st
: TStream
): TSFSVolume
;
107 vt
: TSFSPlainVolumeType
;
108 sign
: packed array [0..3] of Char;
109 dsize
, dofs
: Integer;
114 st
.ReadBuffer(sign
[0], 4);
115 dofs
:= readLongWord(st
);
116 dsize
:= readLongWord(st
);
117 st
.Seek(-12, soCurrent
);
118 if sign
= 'PACK' then
120 if (dsize
< 0) or (dofs
< 0) or (dofs
> st
.Size
) or (dofs
+dsize
> st
.Size
) or (dsize
mod 64 <> 0) then exit
;
123 else if sign
= 'SPAK' then
125 if (dsize
< 0) or (dofs
< 0) or (dofs
> st
.Size
) or (dofs
+dsize
> st
.Size
) or (dsize
mod 64 <> 0) then exit
;
129 result
:= TSFSPlainVolume
.Create(fileName
, st
);
130 TSFSPlainVolume(result
).fType
:= vt
;
132 result
.DoDirectoryRead();
141 pakf
: TSFSPlainVolumeFactory
;
143 pakf
:= TSFSPlainVolumeFactory
.Create();
144 SFSRegisterVolumeFactory(pakf
);
146 // SFSUnregisterVolumeFactory(pakf);