DEADSOFTWARE

more sfs refactoring
[d2df-sdl.git] / src / sfs / sfsPlainFS.pas
1 // Streaming R/O Virtual File System v0.2.0
2 // Copyright (C) XL A.S. Ketmar. All rights reserved
3 // See the file aplicense.txt for conditions of use.
4 //
5 // simple grouping files w/o packing:
6 // Quake I/II .PAK (PACK)
7 // SiN .SIN (SPAK)
8 //
9 {$MODE OBJFPC}
10 {$R+}
11 unit sfsPlainFS;
13 interface
15 uses
16 SysUtils, Classes, Contnrs, sfs;
19 type
20 TSFSPlainVolumeType = (sfspvNone, sfspvPAK, sfspvSIN);
22 TSFSPlainVolume = class (TSFSVolume)
23 protected
24 fType: TSFSPlainVolumeType;
26 procedure ReadDirectory (); override;
28 public
29 function OpenFileByIndex (const index: Integer): TStream; override;
30 end;
32 TSFSPlainVolumeFactory = class (TSFSVolumeFactory)
33 public
34 function IsMyVolumePrefix (const prefix: AnsiString): Boolean; override;
35 function Produce (const prefix, fileName: AnsiString; st: TStream): TSFSVolume; override;
36 procedure Recycle (vol: TSFSVolume); override;
37 end;
40 implementation
42 uses
43 xstreams, utils;
46 { TSFSPlainVolume }
47 procedure TSFSPlainVolume.ReadDirectory ();
48 var
49 dsize, dofs, esz: LongWord;
50 fi: TSFSFileInfo;
51 name: packed array [0..120] of Char;
52 begin
53 if (fType <> sfspvPAK) and (fType <> sfspvSIN) then raise ESFSError.Create('invalid archive');
54 fFileStream.Seek(4, soCurrent); // skip signature
55 fFileStream.ReadBuffer(dofs, 4);
56 fFileStream.ReadBuffer(dsize, 4);
57 fFileStream.Position := dofs;
58 if fType = sfspvPAK then esz := 64 else esz := 128;
59 while dsize >= esz do
60 begin
61 fi := TSFSFileInfo.Create(self);
62 FillChar(name[0], length(name), 0);
63 fFileStream.ReadBuffer(name[0], esz-8);
64 fi.fName := PChar(@name[0]);
65 fFileStream.ReadBuffer(fi.fOfs, 4);
66 fFileStream.ReadBuffer(fi.fSize, 4);
67 Dec(dsize, esz);
68 end;
69 end;
71 function TSFSPlainVolume.OpenFileByIndex (const index: Integer): TStream;
72 begin
73 result := nil;
74 if fFiles = nil then exit;
75 if (index < 0) or (index >= fFiles.Count) or (fFiles[index] = nil) then exit;
76 result := TSFSPartialStream.Create(fFileStream, TSFSFileInfo(fFiles[index]).fOfs, TSFSFileInfo(fFiles[index]).fSize, false);
77 end;
80 { TSFSPlainVolumeFactory }
81 function TSFSPlainVolumeFactory.IsMyVolumePrefix (const prefix: AnsiString): Boolean;
82 begin
83 result :=
84 StrEquCI1251(prefix, 'pak') or
85 StrEquCI1251(prefix, 'sin');
86 end;
88 procedure TSFSPlainVolumeFactory.Recycle (vol: TSFSVolume);
89 begin
90 vol.Free();
91 end;
93 function TSFSPlainVolumeFactory.Produce (const prefix, fileName: AnsiString; st: TStream): TSFSVolume;
94 var
95 vt: TSFSPlainVolumeType;
96 sign: packed array [0..3] of Char;
97 dsize, dofs: Integer;
98 begin
99 result := nil;
100 vt := sfspvNone;
102 st.ReadBuffer(sign[0], 4);
103 st.ReadBuffer(dofs, 4);
104 st.ReadBuffer(dsize, 4);
105 st.Seek(-12, soCurrent);
106 if sign = 'PACK' then
107 begin
108 if (dsize < 0) or (dofs < 0) or (dofs > st.Size) or (dofs+dsize > st.Size) or (dsize mod 64 <> 0) then exit;
109 vt := sfspvPAK;
110 end
111 else if sign = 'SPAK' then
112 begin
113 if (dsize < 0) or (dofs < 0) or (dofs > st.Size) or (dofs+dsize > st.Size) or (dsize mod 64 <> 0) then exit;
114 vt := sfspvSIN;
115 end;
117 result := TSFSPlainVolume.Create(fileName, st);
118 TSFSPlainVolume(result).fType := vt;
119 try
120 result.DoDirectoryRead();
121 except
122 FreeAndNil(result);
123 raise;
124 end;
125 end;
128 var
129 pakf: TSFSPlainVolumeFactory;
130 initialization
131 pakf := TSFSPlainVolumeFactory.Create();
132 SFSRegisterVolumeFactory(pakf);
133 //finalization
134 // SFSUnregisterVolumeFactory(pakf);
135 end.