DEADSOFTWARE

1861c616d0972578f2fcb967dc051dc4e9fc9443
[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 private
89 fFreeMem: Boolean;
90 fMem: Pointer;
92 public
93 constructor Create (pMem: Pointer; pSize: Integer; aFreeMem: Boolean=false);
94 destructor Destroy (); override;
96 function Write (const buffer; count: LongInt): LongInt; override;
97 end;
100 implementation
102 uses
103 sfs; // for ESFSError
105 { TSFSSDLStream }
106 constructor TSFSSDLStream.Create (aSrc: PSDL_RWops; aFreeSource: Boolean=true);
107 begin
108 inherited Create();
109 //ASSERT(aSrc <> nil);
110 fRW := aSrc;
111 fFreeSource := aFreeSource;
112 end;
114 destructor TSFSSDLStream.Destroy ();
115 begin
116 if fFreeSource and (fRW <> nil) then SDL_FreeRW(fRW);
117 inherited Destroy();
118 end;
120 function TSFSSDLStream.Read (var buffer; count: LongInt): LongInt;
121 begin
122 if (fRW = nil) or (count <= 0) then begin result := 0; exit; end;
123 result := SDL_RWread(fRW, @buffer, 1, count);
124 end;
126 function TSFSSDLStream.Write (const buffer; count: LongInt): LongInt;
127 begin
128 if (fRW = nil) or (count <= 0) then begin result := 0; exit; end;
129 result := SDL_RWwrite(fRW, @buffer, 1, count);
130 end;
132 function TSFSSDLStream.Seek (const offset: Int64; origin: TSeekOrigin): Int64;
133 var
134 ss: Integer;
135 begin
136 if fRW = nil then begin result := 0; exit; end;
137 case origin of
138 soBeginning: ss := RW_SEEK_SET;
139 soCurrent: ss := RW_SEEK_CUR;
140 soEnd: ss := RW_SEEK_END;
141 else raise ESFSError.Create('invalid Seek() call');
142 // äðóãèõ íå áûâàåò. à ó êîãî áûâàåò, òîìó ÿ íå äîêòîð.
143 end;
144 result := SDL_RWseek(fRW, offset, ss);
145 if result = -1 then raise ESFSError.Create('Seek() error');
146 end;
149 { TSFSPartialStream }
150 constructor TSFSPartialStream.Create (aSrc: TStream; aPos, aSize: Int64; aKillSrc: Boolean; preBuf: Pointer=nil; bufSz: Integer=0);
151 begin
152 inherited Create();
153 ASSERT(aSrc <> nil);
154 if aPos < 0 then aPos := aSrc.Position;
155 if aSize < 0 then aSize := 0;
156 fSource := aSrc;
157 fKillSource := aKillSrc;
158 fLastReadPos := 0;
159 fCurrentPos := 0;
160 fStartPos := aPos;
161 fSize := aSize;
162 if bufSz > 0 then
163 begin
164 SetLength(fPreBuf, bufSz);
165 Move(preBuf^, fPreBuf[0], bufSz);
166 Inc(fSize, bufSz);
167 end
168 else
169 begin
170 fPreBuf := nil;
171 end;
172 end;
174 destructor TSFSPartialStream.Destroy ();
175 begin
176 if fKillSource then FreeAndNil(fSource);
177 inherited Destroy();
178 end;
180 procedure TSFSPartialStream.CheckPos ();
181 begin
183 if fSource.Position <> fStartPos+fCurrentPos-Length(fPreBuf) then
184 begin
185 fSource.Position := fStartPos+fCurrentPos-Length(fPreBuf);
186 end;
188 if fCurrentPos >= length(fPreBuf) then
189 begin
190 //writeln('seeking at ', fCurrentPos, ' (real: ', fStartPos+fCurrentPos-Length(fPreBuf), ')');
191 fSource.Position := fStartPos+fCurrentPos-Length(fPreBuf);
192 end;
193 fLastReadPos := fCurrentPos;
194 end;
196 function TSFSPartialStream.Write (const buffer; count: LongInt): LongInt;
197 begin
198 result := 0;
199 raise ESFSError.Create('can''t write to read-only stream');
200 // à íå õîäè, íåõîðîøèé, â íàø ñàäèê ãóëÿòü!
201 end;
203 function TSFSPartialStream.Read (var buffer; count: LongInt): LongInt;
204 var
205 left: Int64;
206 pc: Pointer;
207 rd: LongInt;
208 begin
209 if count < 0 then raise ESFSError.Create('invalid Read() call'); // ñêàçî÷íûé äîëáî¸á...
210 if count = 0 then begin result := 0; exit; end;
211 pc := @buffer;
212 result := 0;
213 if (Length(fPreBuf) > 0) and (fCurrentPos < Length(fPreBuf)) then
214 begin
215 fLastReadPos := fCurrentPos;
216 left := Length(fPreBuf)-fCurrentPos;
217 if left > count then left := count;
218 if left > 0 then
219 begin
220 Move(fPreBuf[fCurrentPos], pc^, left);
221 Inc(PChar(pc), left);
222 Inc(fCurrentPos, left);
223 fLastReadPos := fCurrentPos;
224 Dec(count, left);
225 result := left;
226 if count = 0 then exit;
227 end;
228 end;
229 CheckPos();
230 left := fSize-fCurrentPos;
231 if left < count then count := left; // è òàê ñëó÷àåòñÿ...
232 if count > 0 then
233 begin
234 rd := fSource.Read(pc^, count);
235 Inc(result, rd);
236 Inc(fCurrentPos, rd);
237 fLastReadPos := fCurrentPos;
238 end
239 else
240 begin
241 result := 0;
242 end;
243 end;
245 function TSFSPartialStream.Seek (const offset: Int64; origin: TSeekOrigin): Int64;
246 begin
247 case origin of
248 soBeginning: result := offset;
249 soCurrent: result := offset+fCurrentPos;
250 soEnd: result := fSize+offset;
251 else raise ESFSError.Create('invalid Seek() call');
252 // äðóãèõ íå áûâàåò. à ó êîãî áûâàåò, òîìó ÿ íå äîêòîð.
253 end;
254 if result < 0 then result := 0
255 else if result > fSize then result := fSize;
256 fCurrentPos := result;
257 end;
260 { TSFSGuardStream }
261 constructor TSFSGuardStream.Create (aSrc, aGuarded: TStream; aKillSrc, aKillGuarded: Boolean; aGuardedFirst: Boolean=true);
262 begin
263 inherited Create();
264 fSource := aSrc; fGuardedStream := aGuarded;
265 fKillSource := aKillSrc; fKillGuarded := aKillGuarded;
266 fGuardedFirst := aGuardedFirst;
267 end;
269 destructor TSFSGuardStream.Destroy ();
270 begin
271 if fKillGuarded and fGuardedFirst then FreeAndNil(fGuardedStream);
272 if fKillSource then FreeAndNil(fSource);
273 if fKillGuarded and not fGuardedFirst then FreeAndNil(fGuardedStream);
274 inherited Destroy();
275 end;
277 function TSFSGuardStream.Read (var buffer; count: LongInt): LongInt;
278 begin
279 result := fSource.Read(buffer, count);
280 end;
282 function TSFSGuardStream.Write (const buffer; count: LongInt): LongInt;
283 begin
284 result := fSource.Write(buffer, count);
285 end;
287 function TSFSGuardStream.Seek (const offset: Int64; origin: TSeekOrigin): Int64;
288 begin
289 result := fSource.Seek(offset, origin);
290 end;
293 { TSFSMemoryStreamRO }
294 constructor TSFSMemoryStreamRO.Create (pMem: Pointer; pSize: Integer; aFreeMem: Boolean=false);
295 begin
296 fFreeMem := aFreeMem;
297 fMem := pMem;
298 inherited Create();
299 SetPointer(pMem, pSize);
300 Position := 0;
301 end;
303 destructor TSFSMemoryStreamRO.Destroy ();
304 begin
305 if fFreeMem and (fMem <> nil) then FreeMem(fMem);
306 end;
308 function TSFSMemoryStreamRO.Write (const buffer; count: LongInt): LongInt;
309 begin
310 result := 0;
311 raise ESFSError.Create('can''t write to read-only stream');
312 // ñîâñåì ñáðåíäèë...
313 end;
316 end.