zlib-ada/zlib-ada-detect-end-of-zlib-stream-better.patch
2024-02-11 10:53:55 +01:00

134 lines
4.5 KiB
Diff

--- a/zlib-streams.adb
+++ b/zlib-streams.adb
@@ -83,6 +83,7 @@ package body ZLib.Streams is
Stream.Buffer := new Buffer_Subtype;
Stream.Rest_First := Stream.Buffer'Last + 1;
Stream.Rest_Last := Stream.Buffer'Last;
+ Stream.Ahead_Last := Stream.Buffer'First - 1;
end if;
end Create;
@@ -100,9 +101,9 @@ package body ZLib.Streams is
loop
Flush (Stream.Writer, Buffer, Last, Mode);
- Ada.Streams.Write (Stream.Back.all, Buffer (1 .. Last));
+ exit when Last < Buffer'First;
- exit when Last < Buffer'Last;
+ Ada.Streams.Write (Stream.Back.all, Buffer (1 .. Last));
end loop;
end Flush;
@@ -146,8 +147,71 @@ package body ZLib.Streams is
Rest_First => Stream.Rest_First,
Rest_Last => Stream.Rest_Last);
+ Ahead_First : Stream_Element_Offset;
+ Ahead_Last : Stream_Element_Offset;
+
begin
- Read (Stream.Reader, Item, Last);
+ if Stream.Ahead_Last > Stream.Rest_Last then
+ Last := Item'First - 1;
+ Ahead_First := Stream.Rest_Last + 1;
+
+ loop
+ if Last = Item'Last then
+ Ahead_Last :=
+ Stream.Rest_Last + Stream.Ahead_Last - Ahead_First + 1;
+ Stream.Buffer
+ (Stream.Rest_Last + 1 .. Ahead_Last) :=
+ Stream.Buffer (Ahead_First .. Stream.Ahead_Last);
+ Stream.Ahead_Last := Ahead_Last;
+ return;
+ end if;
+
+ Last := Last + 1;
+
+ Item (Last) := Stream.Buffer (Ahead_First);
+
+ if Ahead_First = Stream.Ahead_Last then
+ Stream.Ahead_Last := Stream.Buffer'First - 1;
+ exit;
+ end if;
+
+ Ahead_First := Ahead_First + 1;
+ end loop;
+
+ if Last < Item'Last then
+ Read (Stream.Reader, Item (Last + 1 .. Item'Last), Last);
+ end if;
+
+ else
+ Read (Stream.Reader, Item, Last);
+ end if;
+
+ if not Stream.Reader.Stream_End
+ and then Stream.Rest_First > Stream.Rest_Last
+ then
+ -- Try read ahead to detect end of stream early
+
+ Read (Stream.Buffer.all, Stream.Rest_Last);
+ Stream.Rest_First := Stream.Buffer'First;
+
+ if Stream.Rest_Last = Stream.Buffer'Last then
+ -- No space to read ahead
+ return;
+ end if;
+
+ Translate
+ (Stream.Reader,
+ Stream.Buffer (Stream.Rest_First .. Stream.Rest_Last),
+ In_Last => Stream.Rest_First,
+ Out_Data =>
+ Stream.Buffer (Stream.Rest_Last + 1 .. Stream.Buffer'Last),
+ Out_Last => Stream.Ahead_Last,
+ Flush => (if Stream.Rest_First > Stream.Rest_Last
+ then Finish
+ else No_Flush));
+
+ Stream.Rest_First := Stream.Rest_First + 1;
+ end if;
end Read;
-------------------
--- a/zlib-streams.ads
+++ b/zlib-streams.ads
@@ -91,6 +91,11 @@ private
-- We need to have this buffer in the record because not all read data
-- from back stream could be processed during the read operation.
+ Ahead_Last : Stream_Element_Offset;
+ -- Sometimes the decompressed data is over but the gzip footer still was
+ -- not read from back stream. We should try to read ahead in case we are
+ -- suspect this to detect end of stream proper.
+
Buffer_Size : Stream_Element_Offset;
-- Buffer size for write operation.
-- We do not need to have this buffer in the record because all data
@@ -102,6 +107,8 @@ private
end record;
function End_Of_Stream (Stream : in Stream_Type) return Boolean is
- (Stream_End (Stream.Reader));
+ (Stream_End (Stream.Reader)
+ and then Stream.Rest_First > Stream.Rest_Last
+ and then Stream.Rest_Last >= Stream.Ahead_Last);
end ZLib.Streams;
--- a/zlib.ads
+++ b/zlib.ads
@@ -263,8 +263,10 @@ package ZLib is
Rest_First, Rest_Last : in out Stream_Element_Offset;
-- Rest_First have to be initialized to Buffer'Last + 1
- -- Rest_Last have to be initialized to Buffer'Last
- -- before usage.
+ -- Rest_Last have to be initialized to Buffer'Last before usage.
+ -- When no more data provided with first generic parameter procedure
+ -- Read then the Read_First became Buffer'First and the Read_Last became
+ -- Buffer'First - 1.
Allow_Read_Some : in Boolean := False;
-- Is it allowed to return Last < Item'Last before end of data