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)
27 SysUtils
, Classes
, Contnrs
, sfs
;
31 TSFSPlainVolumeType
= (sfspvNone
, sfspvPAK
, sfspvSIN
);
33 TSFSPlainVolume
= class (TSFSVolume
)
35 fType
: TSFSPlainVolumeType
;
37 procedure ReadDirectory (); override;
40 function OpenFileByIndex (const index
: Integer): TStream
; override;
43 TSFSPlainVolumeFactory
= class (TSFSVolumeFactory
)
45 function IsMyVolumePrefix (const prefix
: AnsiString): Boolean; override;
46 function Produce (const prefix
, fileName
: AnsiString; st
: TStream
): TSFSVolume
; override;
47 procedure Recycle (vol
: TSFSVolume
); override;
58 procedure TSFSPlainVolume
.ReadDirectory ();
60 dsize
, dofs
, esz
: LongWord;
62 name
: packed array [0..120] of Char;
64 if (fType
<> sfspvPAK
) and (fType
<> sfspvSIN
) then raise ESFSError
.Create('invalid archive');
65 fFileStream
.Seek(4, soCurrent
); // skip signature
66 dofs
:= readLongWord(fFileStream
);
67 dsize
:= readLongWord(fFileStream
);
68 fFileStream
.Position
:= dofs
;
69 if fType
= sfspvPAK
then esz
:= 64 else esz
:= 128;
72 fi
:= TSFSFileInfo
.Create(self
);
73 FillChar(name
[0], length(name
), 0);
74 fFileStream
.ReadBuffer(name
[0], esz
-8);
75 fi
.fName
:= PChar(@name
[0]);
76 fi
.fOfs
:= readLongWord(fFileStream
);
77 fi
.fSize
:= readLongWord(fFileStream
);
82 function TSFSPlainVolume
.OpenFileByIndex (const index
: Integer): TStream
;
85 if fFiles
= nil then exit
;
86 if (index
< 0) or (index
>= fFiles
.Count
) or (fFiles
[index
] = nil) then exit
;
87 result
:= TSFSPartialStream
.Create(fFileStream
, TSFSFileInfo(fFiles
[index
]).fOfs
, TSFSFileInfo(fFiles
[index
]).fSize
, false);
91 { TSFSPlainVolumeFactory }
92 function TSFSPlainVolumeFactory
.IsMyVolumePrefix (const prefix
: AnsiString): Boolean;
95 StrEquCI1251(prefix
, 'pak') or
96 StrEquCI1251(prefix
, 'sin');
99 procedure TSFSPlainVolumeFactory
.Recycle (vol
: TSFSVolume
);
104 function TSFSPlainVolumeFactory
.Produce (const prefix
, fileName
: AnsiString; st
: TStream
): TSFSVolume
;
106 vt
: TSFSPlainVolumeType
;
107 sign
: packed array [0..3] of Char;
108 dsize
, dofs
: Integer;
113 st
.ReadBuffer(sign
[0], 4);
114 dofs
:= readLongWord(st
);
115 dsize
:= readLongWord(st
);
116 st
.Seek(-12, soCurrent
);
117 if sign
= 'PACK' then
119 if (dsize
< 0) or (dofs
< 0) or (dofs
> st
.Size
) or (dofs
+dsize
> st
.Size
) or (dsize
mod 64 <> 0) then exit
;
122 else if sign
= 'SPAK' then
124 if (dsize
< 0) or (dofs
< 0) or (dofs
> st
.Size
) or (dofs
+dsize
> st
.Size
) or (dsize
mod 64 <> 0) then exit
;
128 result
:= TSFSPlainVolume
.Create(fileName
, st
);
129 TSFSPlainVolume(result
).fType
:= vt
;
131 result
.DoDirectoryRead();
140 pakf
: TSFSPlainVolumeFactory
;
142 pakf
:= TSFSPlainVolumeFactory
.Create();
143 SFSRegisterVolumeFactory(pakf
);
145 // SFSUnregisterVolumeFactory(pakf);