X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fshared%2Fxstreams.pas;h=1668518eeab8b992b96800522f17b93ee977c34d;hb=345e116f73d0e4b11593a94bee7d18b9e64572eb;hp=5e026e19e6ef9b196087a62e7d5f59d762fd654a;hpb=ac201b02f10ef558087d50f6b03b4519ab567558;p=d2df-sdl.git diff --git a/src/shared/xstreams.pas b/src/shared/xstreams.pas index 5e026e1..1668518 100644 --- a/src/shared/xstreams.pas +++ b/src/shared/xstreams.pas @@ -1,6 +1,21 @@ +(* Copyright (C) DooM 2D:Forever Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *) // special stream classes -{$MODE DELPHI} -{$R+} +{$INCLUDE a_modes.inc} +{.$R+} unit xstreams; interface @@ -111,6 +126,29 @@ type function seek (const offset: Int64; origin: TSeekOrigin): Int64; override; end; + // fixed memory chunk + TSFSMemoryChunkStream = class(TStream) + private + fFreeMem: Boolean; + fMemBuf: PByte; + fMemSize: Integer; + fCurPos: Integer; + + public + // if `pMem` is `nil`, stream will allocate it + constructor Create (pMem: Pointer; pSize: Integer; aFreeMem: Boolean=false); + destructor Destroy (); override; + + procedure setup (pMem: Pointer; pSize: Integer; aFreeMem: Boolean=false); + + function Seek (const offset: Int64; origin: TSeekOrigin): Int64; override; + function Read (var buffer; count: LongInt): LongInt; override; + function Write (const buffer; count: LongInt): LongInt; override; + + property chunkSize: Integer read fMemSize; + property chunkData: PByte read fMemBuf; + end; + implementation @@ -301,9 +339,10 @@ begin fSize := aSize; GetMem(fBuffer, ZBufSize); fSkipHeader := aSkipHeader; + fSrcStPos := fSrcSt.position; + FillChar(fZlibSt, sizeof(fZlibSt), 0); if fSkipHeader then err := inflateInit2(fZlibSt, -MAX_WBITS) else err := inflateInit(fZlibSt); if err <> Z_OK then raise XStreamError.Create(zerror(err)); - fSrcStPos := fSrcSt.position; end; @@ -319,29 +358,31 @@ end; function TUnZStream.readBuf (var buffer; count: LongInt): LongInt; var err: Integer; - lastavail: LongInt; + sz: LongInt; begin - fZlibSt.next_out := @buffer; - fZlibSt.avail_out := count; - lastavail := count; - while fZlibSt.avail_out <> 0 do + result := 0; + if (fSize >= 0) and (fPos >= fSize) then exit; + if count > 0 then begin - if fZlibSt.avail_in = 0 then + fZlibSt.next_out := @buffer; + fZlibSt.avail_out := count; + sz := fZlibSt.avail_out; + while fZlibSt.avail_out > 0 do begin - // refill the buffer - fZlibSt.next_in := fBuffer; - fZlibSt.avail_in := fSrcSt.read(Fbuffer^, ZBufSize); - //Inc(compressed_read, fZlibSt.avail_in); - Inc(fPos, lastavail-fZlibSt.avail_out); - lastavail := fZlibSt.avail_out; + if fZlibSt.avail_in = 0 then + begin + // refill the buffer + fZlibSt.next_in := fBuffer; + fZlibSt.avail_in := fSrcSt.read(Fbuffer^, ZBufSize); + end; + err := inflate(fZlibSt, Z_NO_FLUSH); + if (err <> Z_OK) and (err <> Z_STREAM_END) then raise XStreamError.Create(zerror(err)); + Inc(result, sz-fZlibSt.avail_out); + Inc(fPos, sz-fZlibSt.avail_out); + sz := fZlibSt.avail_out; + if err = Z_STREAM_END then begin fSize := fPos; break; end; end; - err := inflate(fZlibSt, Z_NO_FLUSH); - if err = Z_STREAM_END then fSize := fPos; break; - if err <> Z_OK then raise XStreamError.Create(zerror(err)); end; - //if err = Z_STREAM_END then Dec(compressed_read, fZlibSt.avail_in); - Inc(fPos, lastavail-fZlibSt.avail_out); - result := count-fZlibSt.avail_out; end; @@ -359,7 +400,7 @@ begin //writeln(' reading ', rd, ' bytes...'); rr := readBuf(buf, rd); //writeln(' got ', rr, ' bytes; fPos=', fPos, '; fSkipToPos=', fSkipToPos); - if rd <> rr then raise XStreamError.Create('seek error'); + if rr <= 0 then raise XStreamError.Create('seek error'); end; //writeln(' pos: fPos=', fPos, '; fSkipToPos=', fSkipToPos); fSkipToPos := -1; @@ -379,12 +420,12 @@ begin while true do begin rd := readBuf(buf, 4096); - if rd <> 4096 then break; + if rd = 0 then break; end; fSize := fPos; //writeln(' unzstream size is ', fSize); finally - fSkipToPos := opos; + if fSkipToPos < 0 then fSkipToPos := opos; end; end; @@ -407,9 +448,11 @@ procedure TUnZStream.reset (); var err: Integer; begin + //writeln('doing RESET'); fSrcSt.position := fSrcStPos; fPos := 0; inflateEnd(fZlibSt); + FillChar(fZlibSt, sizeof(fZlibSt), 0); if fSkipHeader then err := inflateInit2(fZlibSt, -MAX_WBITS) else err := inflateInit(fZlibSt); if err <> Z_OK then raise XStreamError.Create(zerror(err)); end; @@ -434,4 +477,91 @@ begin end; +// ////////////////////////////////////////////////////////////////////////// // +constructor TSFSMemoryChunkStream.Create (pMem: Pointer; pSize: Integer; aFreeMem: Boolean=false); +begin + fMemBuf := nil; + fFreeMem := false; + fMemSize := 0; + fCurPos := 0; + setup(pMem, pSize, aFreeMem); +end; + + +procedure TSFSMemoryChunkStream.setup (pMem: Pointer; pSize: Integer; aFreeMem: Boolean=false); +begin + if fFreeMem then FreeMem(fMemBuf); + fMemBuf := nil; + fFreeMem := false; + fMemSize := 0; + fCurPos := 0; + if (pSize < 0) then raise XStreamError.Create('invalid chunk size'); + if (pMem = nil) then + begin + if (pSize > 0) then + begin + GetMem(pMem, pSize); + if (pMem = nil) then raise XStreamError.Create('out of memory for chunk'); + aFreeMem := true; + end + else + begin + aFreeMem := false; + end; + end; + fFreeMem := aFreeMem; + fMemBuf := PByte(pMem); + fMemSize := pSize; +end; + + +destructor TSFSMemoryChunkStream.Destroy (); +begin + if fFreeMem then FreeMem(fMemBuf); + inherited; +end; + + +function TSFSMemoryChunkStream.Seek (const offset: Int64; origin: TSeekOrigin): Int64; +begin + case origin of + soBeginning: result := offset; + soCurrent: result := offset+fCurPos; + soEnd: result := fMemSize+offset; + else raise XStreamError.Create('invalid Seek() call'); + end; + if (result < 0) then raise XStreamError.Create('invalid Seek() call'); + if (result > fMemSize) then result := fMemSize; + fCurPos := result; +end; + + +function TSFSMemoryChunkStream.Read (var buffer; count: LongInt): LongInt; +var + left: Integer; +begin + if (count < 0) then raise XStreamError.Create('negative read'); + left := fMemSize-fCurPos; + if (left < 0) then raise XStreamError.Create('internal error in TSFSMemoryChunkStream (read)'); + if (count > left) then count := left; + if (count > 0) then Move((fMemBuf+fCurPos)^, buffer, count); + Inc(fCurPos, count); + result := count; +end; + + +function TSFSMemoryChunkStream.Write (const buffer; count: LongInt): LongInt; +var + left: Integer; +begin + if (count < 0) then raise XStreamError.Create('negative write'); + left := fMemSize-fCurPos; + if (left < 0) then raise XStreamError.Create('internal error in TSFSMemoryChunkStream (write)'); + if (count > left) then count := left; + if (count > 0) then Move(buffer, (fMemBuf+fCurPos)^, count); + Inc(fCurPos, count); + result := count; +end; + + end.