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.
5 // "memory group". reads the whole pack in memory (and decompress it if
6 // necessary). memory image has only one file named "<body>".
9 // slh!: DOS Allegro "slh!"
10 // mem : raw file (no processing, just read)
11 // as a side effect this gives us an opportunity to read enclosed packs
12 // from the packs which aren't supporting backseeking (such as zips).
21 SysUtils
, Classes
, Contnrs
, sfs
;
25 TSFSMemVolumeType
= (sfsmvNone
, sfsmvRAW
, sfsmvSLH
);
27 TSFSMemoryVolume
= class(TSFSVolume
)
29 fType
: TSFSMemVolumeType
;
30 fMemStream
: TMemoryStream
;
35 procedure ReadDirectory (); override;
36 function OpenFileByIndex (const index
: Integer): TStream
; override;
39 TSFSMemoryVolumeFactory
= class (TSFSVolumeFactory
)
41 function IsMyVolumePrefix (const prefix
: TSFSString
): Boolean; override;
42 function Produce (const prefix
, fileName
: TSFSString
; st
: TStream
): TSFSVolume
; override;
43 procedure Recycle (vol
: TSFSVolume
); override;
54 function SLHCheckMagic (st
: TStream
): Boolean;
56 sign
: packed array [0..3] of Char;
59 st
.ReadBuffer(sign
[0], 4);
60 st
.Seek(-4, soCurrent
);
61 if sign
<> 'slh!' then exit
;
67 procedure TSFSMemoryVolume
.RAWRead ();
71 fMemStream
.CopyFrom(fFileStream
, 0); // voila %-)
72 fi
:= TSFSFileInfo
.Create(self
);
74 fi
.fSize
:= fMemStream
.Size
;
77 procedure TSFSMemoryVolume
.SLHRead ();
78 // unpack LZSS-packed file
81 bufi
, bufo
: packed array of Byte;
82 iused
, oused
, rpos
: Integer;
83 dict
: packed array of Byte;
84 flags
, dpos
, pos
, len
: Word;
87 function ReadCh (): Integer;
92 if fFileStream
.Size
-fFileStream
.Position
> Length(bufi
) then iused
:= Length(bufi
)
93 else iused
:= fFileStream
.Size
-fFileStream
.Position
;
95 if iused
> 0 then fFileStream
.ReadBuffer(bufi
[0], iused
);
98 if iused
= 0 then result
:= -1
99 else begin result
:= bufi
[rpos
]; Inc(rpos
); end;
102 procedure WriteCh (c
: Byte);
104 if oused
>= Length(bufo
) then
106 fMemStream
.WriteBuffer(bufo
[0], oused
);
109 bufo
[oused
] := c
; Inc(oused
);
110 dict
[dpos
] := c
; dpos
:= (dpos
+1) and $FFF;
114 fFileStream
.Seek(4, soCurrent
); // skip signature
115 SetLength(bufi
, 65536); SetLength(bufo
, 65536); SetLength(dict
, 4096);
116 rpos
:= 0; iused
:= 0; oused
:= 0;
117 flags
:= 0; dpos
:= 4096-18;
119 if (flags
and $FF00) = 0 then
121 c
:= ReadCh(); if c
= -1 then break
;
125 if (flags
and $01) <> 0 then
128 c
:= ReadCh(); if c
= -1 then break
;
134 c
:= ReadCh(); if c
= -1 then break
;
136 c
:= ReadCh(); if c
= -1 then break
;
138 pos
:= (pos
and $FF) or ((len
and $F0) shl 4); len
:= (len
and $0F)+3;
141 c
:= dict
[pos
]; pos
:= (pos
+1) and $FFF; Dec(len
);
145 flags
:= flags
shr 1;
147 if oused
> 0 then fMemStream
.WriteBuffer(bufo
[0], oused
);
149 fi
:= TSFSFileInfo
.Create(self
);
150 fi
.fName
:= '<body>';
151 fi
.fSize
:= fMemStream
.Size
;
154 procedure TSFSMemoryVolume
.ReadDirectory ();
156 if fMemStream
= nil then fMemStream
:= TMemoryStream
.Create()
159 fMemStream
.Position
:= 0; fMemStream
.Size
:= 0;
165 else raise ESFSError
.Create('invalid memory SFS');
168 fMemStream
.Position
:= 0;
171 function TSFSMemoryVolume
.OpenFileByIndex (const index
: Integer): TStream
;
175 result
:= nil; fs
:= nil;
176 if fFiles
= nil then exit
;
177 if (index
< 0) or (index
>= fFiles
.Count
) or (fFiles
[index
] = nil) then exit
;
180 fs
:= TSFSMemoryStreamRO
.Create(fMemStream
.Memory
, fMemStream
.Size
);
181 if fFiles
.Count
= 1 then
188 result
:= TSFSPartialStream
.Create(fs
,
189 TSFSFileInfo(fFiles
[index
]).fOfs
,
190 TSFSFileInfo(fFiles
[index
]).fSize
, true);
202 { TSFSMemoryVolumeFactory }
203 function TSFSMemoryVolumeFactory
.IsMyVolumePrefix (const prefix
: TSFSString
): Boolean;
206 (SFSStrComp(prefix
, 'mem') = 0) or
207 (SFSStrComp(prefix
, 'slh!') = 0);
210 procedure TSFSMemoryVolumeFactory
.Recycle (vol
: TSFSVolume
);
215 function TSFSMemoryVolumeFactory
.Produce (const prefix
, fileName
: TSFSString
; st
: TStream
): TSFSVolume
;
217 vt
: TSFSMemVolumeType
;
219 if (prefix
<> 'mem') and SLHCheckMagic(st
) then vt
:= sfsmvSLH
220 else if prefix
<> '' then vt
:= sfsmvRAW
221 else vt
:= sfsmvNone
;
223 result
:= TSFSMemoryVolume
.Create(fileName
, st
);
224 TSFSMemoryVolume(result
).fType
:= vt
;
226 result
.DoDirectoryRead();
235 memf
: TSFSMemoryVolumeFactory
;
237 memf
:= TSFSMemoryVolumeFactory
.Create();
238 SFSRegisterVolumeFactory(memf
);
240 SFSUnregisterVolumeFactory(memf
);