DEADSOFTWARE

sfs: multiple files fix
[d2df-sdl.git] / src / sfs / xstreams.pas
1 // special stream classes
2 {$MODE DELPHI}
3 {.$R-}
4 unit xstreams;
6 interface
8 uses
9 SysUtils, Classes, SDL2;
12 type
13 // ïîòîê-îá¸ðòêà äëÿ SDL_RWops
14 TSFSSDLStream = class(TStream)
15 protected
16 fRW: PSDL_RWops; // SDL-íàÿ ïðîêëàäêà
17 fFreeSource: Boolean; // óáèâàòü èñõîäíèê ïðè ïîìèðàíèè?
19 public
20 constructor Create (aSrc: PSDL_RWops; aFreeSource: Boolean=true);
21 destructor Destroy (); override;
23 function Read (var buffer; count: LongInt): LongInt; override;
24 function Write (const buffer; count: LongInt): LongInt; override;
25 function Seek (const offset: Int64; origin: TSeekOrigin): Int64; override;
26 end;
28 // read-only ïîòîê äëÿ èçâëå÷åíèÿ èç èñõîäíîãî òîëüêî êóñî÷êà
29 TSFSPartialStream = class(TStream)
30 protected
31 fSource: TStream; // èñõîäíûé ïîòîê
32 fKillSource: Boolean; // óáèâàòü èñõîäíèê ïðè ïîìèðàíèè?
33 fLastReadPos: Int64; // ïîñëåäíèé Read() îñòàíîâèëñÿ çäåñü (îòíîñ. fStartPos)
34 fCurrentPos: Int64; // ïîñëåäíèé Seek() îñòàíîâèëñÿ çäåñü (îòíîñ. fStartPos)
35 fStartPos: Int64; // íà÷àëî êóñî÷êà
36 fSize: Int64; // äëèíà êóñî÷êà
37 fPreBuf: packed array of Byte; // ýòîò áóôåð áóäåò ïåðåä ôàéëîì
39 procedure CheckPos ();
41 public
42 // aSrc: ïîòîê-èñõîäíèê.
43 // aPos: íà÷àëüíàÿ ïîçèöèÿ â ïîòîêå. -1 -- ñ òåêóùåé.
44 // åñëè aPos < òåêóùåé ïîçèöèè, òî èñõîäíûé ïîòîê äîëæåí
45 // íîðìàëüíî ïîääåðæèâàòü Seek()!
46 // aSize: êîëè÷åñòâî áàéòèêîâ, êîòîðîå ìîæíî ïðî÷åñòü èç ïîòîêà.
47 // åñëè ìåíüøå íóëÿ -- òî äî êîíöà.
48 // aKillSrc: óáèâàòü ëè èñõîäíûé ïîòîê, êîãäà ñàìè óìèðàåì?
49 // òàêæå ìîæåò ïðèøïàíäîðèòü ê íà÷àëó ôàéëà áóôåð. bufSz áóäåò äîáàâëåíî ê
50 // äëèíå ôàéëà.
51 constructor Create (aSrc: TStream; aPos, aSize: Int64; aKillSrc: Boolean; preBuf: Pointer=nil; bufSz: Integer=0);
52 destructor Destroy (); override;
54 // íîðìàëèçóåò count è ÷èòàåò.
55 function Read (var buffer; count: LongInt): LongInt; override;
56 // Write() ïðîñòî ãðîìêî ïàäàåò.
57 function Write (const buffer; count: LongInt): LongInt; override;
58 // Seek() ðåàëèçîâàíî, ÷òîáû ìîãëà ðàáîòàòü ïðîïåðòÿ Size.
59 // âîîáùå-òî ìîæíî ïåðåêðûòü ìåòîä GetSize(), íî âäðóã êàêîé
60 // áîëüíîé íà ãîëîâó êîäåð áóäåò ïîëó÷àòü ðàçìåð ïðè ïîìîùè
61 // Seek()'à?
62 function Seek (const offset: Int64; origin: TSeekOrigin): Int64; override;
63 end;
65 TSFSGuardStream = class(TStream)
66 protected
67 fSource: TStream; // èñõîäíûé ïîòîê
68 fGuardedStream: TStream; // ïîòîê, êîòîðûé çàâàëèì ïðè ïîìèðàíèè
69 fKillSource: Boolean; // óáèâàòü èñõîäíèê ïðè ïîìèðàíèè?
70 fKillGuarded: Boolean; // óáèâàòü îõðàíÿåìûé ïðè ïîìèðàíèè?
71 fGuardedFirst: Boolean; // ïðè ñìåðòè ïåðâûì ïðèøèáàåì îõðàíÿåìîãî?
73 public
74 // aSrc: ïîòîê-èñõîäíèê (íà êîòîðûé çàìàïåíû îïåðàöèè ÷òåíèÿ/çàïèñè).
75 // aKillSrc: óáèâàòü ëè èñõîäíûé ïîòîê, êîãäà ñàìè óìèðàåì?
76 // aKillGuarded: óáèâàòü ëè îõðàíÿåìûé ïîòîê, êîãäà ñàìè óìèðàåì?
77 // aGuardedFirst: true: ïðè ñìåðòè ïåðâûì ïðèøèáàåì îõðàíÿåìîãî.
78 constructor Create (aSrc, aGuarded: TStream; aKillSrc, aKillGuarded: Boolean; aGuardedFirst: Boolean=true);
79 destructor Destroy (); override;
81 // íèæåñëåäóþùåå çàìàïëåíî íà fSource
82 function Read (var buffer; count: LongInt): LongInt; override;
83 function Write (const buffer; count: LongInt): LongInt; override;
84 function Seek (const offset: Int64; origin: TSeekOrigin): Int64; override;
85 end;
87 TSFSMemoryStreamRO = class(TCustomMemoryStream)
88 public
89 constructor Create (pMem: Pointer; pSize: Integer);
91 function Write (const buffer; count: LongInt): LongInt; override;
92 end;
95 implementation
97 uses
98 sfs; // for ESFSError
100 { TSFSSDLStream }
101 constructor TSFSSDLStream.Create (aSrc: PSDL_RWops; aFreeSource: Boolean=true);
102 begin
103 inherited Create();
104 //ASSERT(aSrc <> nil);
105 fRW := aSrc;
106 fFreeSource := aFreeSource;
107 end;
109 destructor TSFSSDLStream.Destroy ();
110 begin
111 if fFreeSource and (fRW <> nil) then SDL_FreeRW(fRW);
112 inherited Destroy();
113 end;
115 function TSFSSDLStream.Read (var buffer; count: LongInt): LongInt;
116 begin
117 if (fRW = nil) or (count <= 0) then begin result := 0; exit; end;
118 result := SDL_RWread(fRW, @buffer, 1, count);
119 end;
121 function TSFSSDLStream.Write (const buffer; count: LongInt): LongInt;
122 begin
123 if (fRW = nil) or (count <= 0) then begin result := 0; exit; end;
124 result := SDL_RWwrite(fRW, @buffer, 1, count);
125 end;
127 function TSFSSDLStream.Seek (const offset: Int64; origin: TSeekOrigin): Int64;
128 var
129 ss: Integer;
130 begin
131 if fRW = nil then begin result := 0; exit; end;
132 case origin of
133 soBeginning: ss := RW_SEEK_SET;
134 soCurrent: ss := RW_SEEK_CUR;
135 soEnd: ss := RW_SEEK_END;
136 else raise ESFSError.Create('invalid Seek() call');
137 // äðóãèõ íå áûâàåò. à ó êîãî áûâàåò, òîìó ÿ íå äîêòîð.
138 end;
139 result := SDL_RWseek(fRW, offset, ss);
140 if result = -1 then raise ESFSError.Create('Seek() error');
141 end;
144 { TSFSPartialStream }
145 constructor TSFSPartialStream.Create (aSrc: TStream; aPos, aSize: Int64; aKillSrc: Boolean; preBuf: Pointer=nil; bufSz: Integer=0);
146 begin
147 inherited Create();
148 ASSERT(aSrc <> nil);
149 if aPos < 0 then aPos := aSrc.Position;
150 if aSize < 0 then aSize := 0;
151 fSource := aSrc;
152 fKillSource := aKillSrc;
153 fLastReadPos := 0;
154 fCurrentPos := 0;
155 fStartPos := aPos;
156 fSize := aSize;
157 if bufSz > 0 then
158 begin
159 SetLength(fPreBuf, bufSz);
160 Move(preBuf^, fPreBuf[0], bufSz);
161 Inc(fSize, bufSz);
162 end
163 else
164 begin
165 fPreBuf := nil;
166 end;
167 end;
169 destructor TSFSPartialStream.Destroy ();
170 begin
171 if fKillSource then FreeAndNil(fSource);
172 inherited Destroy();
173 end;
175 procedure TSFSPartialStream.CheckPos ();
176 begin
178 if fSource.Position <> fStartPos+fCurrentPos-Length(fPreBuf) then
179 begin
180 fSource.Position := fStartPos+fCurrentPos-Length(fPreBuf);
181 end;
183 if fCurrentPos >= length(fPreBuf) then
184 begin
185 //writeln('seeking at ', fCurrentPos, ' (real: ', fStartPos+fCurrentPos-Length(fPreBuf), ')');
186 fSource.Position := fStartPos+fCurrentPos-Length(fPreBuf);
187 end;
188 fLastReadPos := fCurrentPos;
189 end;
191 function TSFSPartialStream.Write (const buffer; count: LongInt): LongInt;
192 begin
193 result := 0;
194 raise ESFSError.Create('can''t write to read-only stream');
195 // à íå õîäè, íåõîðîøèé, â íàø ñàäèê ãóëÿòü!
196 end;
198 function TSFSPartialStream.Read (var buffer; count: LongInt): LongInt;
199 var
200 left: Int64;
201 pc: Pointer;
202 rd: LongInt;
203 begin
204 if count < 0 then raise ESFSError.Create('invalid Read() call'); // ñêàçî÷íûé äîëáî¸á...
205 if count = 0 then begin result := 0; exit; end;
206 pc := @buffer;
207 result := 0;
208 if (Length(fPreBuf) > 0) and (fCurrentPos < Length(fPreBuf)) then
209 begin
210 fLastReadPos := fCurrentPos;
211 left := Length(fPreBuf)-fCurrentPos;
212 if left > count then left := count;
213 if left > 0 then
214 begin
215 Move(fPreBuf[fCurrentPos], pc^, left);
216 Inc(PChar(pc), left);
217 Inc(fCurrentPos, left);
218 fLastReadPos := fCurrentPos;
219 Dec(count, left);
220 result := left;
221 if count = 0 then exit;
222 end;
223 end;
224 CheckPos();
225 left := fSize-fCurrentPos;
226 if left < count then count := left; // è òàê ñëó÷àåòñÿ...
227 if count > 0 then
228 begin
229 rd := fSource.Read(pc^, count);
230 Inc(result, rd);
231 Inc(fCurrentPos, rd);
232 fLastReadPos := fCurrentPos;
233 end
234 else
235 begin
236 result := 0;
237 end;
238 end;
240 function TSFSPartialStream.Seek (const offset: Int64; origin: TSeekOrigin): Int64;
241 begin
242 case origin of
243 soBeginning: result := offset;
244 soCurrent: result := offset+fCurrentPos;
245 soEnd: result := fSize+offset;
246 else raise ESFSError.Create('invalid Seek() call');
247 // äðóãèõ íå áûâàåò. à ó êîãî áûâàåò, òîìó ÿ íå äîêòîð.
248 end;
249 if result < 0 then result := 0
250 else if result > fSize then result := fSize;
251 fCurrentPos := result;
252 end;
255 { TSFSGuardStream }
256 constructor TSFSGuardStream.Create (aSrc, aGuarded: TStream; aKillSrc, aKillGuarded: Boolean; aGuardedFirst: Boolean=true);
257 begin
258 inherited Create();
259 fSource := aSrc; fGuardedStream := aGuarded;
260 fKillSource := aKillSrc; fKillGuarded := aKillGuarded;
261 fGuardedFirst := aGuardedFirst;
262 end;
264 destructor TSFSGuardStream.Destroy ();
265 begin
266 if fKillGuarded and fGuardedFirst then FreeAndNil(fGuardedStream);
267 if fKillSource then FreeAndNil(fSource);
268 if fKillGuarded and not fGuardedFirst then FreeAndNil(fGuardedStream);
269 inherited Destroy();
270 end;
272 function TSFSGuardStream.Read (var buffer; count: LongInt): LongInt;
273 begin
274 result := fSource.Read(buffer, count);
275 end;
277 function TSFSGuardStream.Write (const buffer; count: LongInt): LongInt;
278 begin
279 result := fSource.Write(buffer, count);
280 end;
282 function TSFSGuardStream.Seek (const offset: Int64; origin: TSeekOrigin): Int64;
283 begin
284 result := fSource.Seek(offset, origin);
285 end;
288 { TSFSMemoryStreamRO }
289 constructor TSFSMemoryStreamRO.Create (pMem: Pointer; pSize: Integer);
290 begin
291 inherited Create();
292 SetPointer(pMem, pSize);
293 Position := 0;
294 end;
296 function TSFSMemoryStreamRO.Write (const buffer; count: LongInt): LongInt;
297 begin
298 result := 0;
299 raise ESFSError.Create('can''t write to read-only stream');
300 // ñîâñåì ñáðåíäèë...
301 end;
304 end.