DEADSOFTWARE

xstreams: fixed seeking in compressed stream
[d2df-sdl.git] / src / shared / xstreams.pas
index abf8bec0e731e8e5da1f2c12f12241acb862a033..270d292e88bc80464d699d34951672e4bfa1b4e4 100644 (file)
@@ -1,5 +1,5 @@
 // special stream classes
-{$MODE OBJFPC}
+{$MODE DELPHI}
 {$R+}
 unit xstreams;
 
@@ -301,9 +301,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 +320,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 +362,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 rd <= 0 then raise XStreamError.Create('seek error');
   end;
   //writeln('  pos: fPos=', fPos, '; fSkipToPos=', fSkipToPos);
   fSkipToPos := -1;
@@ -379,12 +382,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 +410,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;