Browse Source

+ Patch to support sizeless streams by Sebastian Guenter

michael 26 years ago
parent
commit
4f4354e276
3 changed files with 87 additions and 39 deletions
  1. 79 35
      fcl/inc/base64.pp
  2. 1 1
      fcl/tests/README
  3. 7 3
      fcl/tests/b64dec.pp

+ 79 - 35
fcl/inc/base64.pp

@@ -32,15 +32,18 @@ type
   TBase64DecodingStream = class(TStream)
   protected
     InputStream: TStream;
-    CurPos, DataLen: LongInt;
+    CurPos, InputStreamSize: LongInt;
     Buf: array[0..2] of Byte;
     BufPos: Integer;    // Offset of byte which is to be read next
+    fEOF: Boolean;
   public
     constructor Create(AInputStream: TStream);
+    procedure Reset;
 
     function Read(var Buffer; Count: Longint): Longint; override;
     function Write(const Buffer; Count: Longint): Longint; override;
     function Seek(Offset: Longint; Origin: Word): Longint; override;
+    property EOF: Boolean read fEOF;
   end;
 
 
@@ -153,25 +156,17 @@ end;
 
 
 constructor TBase64DecodingStream.Create(AInputStream: TStream);
-var
-  ipos: LongInt;
-  endbytes: array[0..1] of Char;
 begin
   inherited Create;
   InputStream := AInputStream;
-  BufPos := 3;
-
-  ipos := InputStream.Position;
-  DataLen := ((InputStream.Size - ipos + 3) div 4) * 3;
-  InputStream.Seek(-2, soFromEnd);
-  InputStream.Read(endbytes, 2);
-  InputStream.Position := ipos;
+  Reset;
+end;
 
-  if endbytes[1] = '=' then begin
-    Dec(DataLen);
-    if endbytes[0] = '=' then
-      Dec(DataLen);
-  end;
+procedure TBase64DecodingStream.Reset;
+begin
+  InputStreamSize := -1;
+  BufPos := 3;
+  fEOF := False;
 end;
 
 function TBase64DecodingStream.Read(var Buffer; Count: Longint): Longint;
@@ -179,36 +174,62 @@ var
   p: PChar;
   b: Char;
   ReadBuf: array[0..3] of Byte;
-  ToRead, ReadOK, i, j: Integer;
+  ToRead, OrgToRead, HaveRead, ReadOK, i, j: Integer;
 begin
   if Count <= 0 then exit(0);
-  if CurPos + Count > DataLen then
-    Count := DataLen - CurPos;
-  if Count <= 0 then exit(0);
+  if InputStreamSize <> -1 then begin
+    if CurPos + Count > InputStreamSize then
+      Count := InputStreamSize - CurPos;
+    if Count <= 0 then exit(0);
+  end;
 
-  Result := Count;
+  Result := 0;
   p := PChar(@Buffer);
-  while Count > 0 do begin
+  while (Count > 0) and not fEOF do begin
     if BufPos > 2 then begin
       BufPos := 0;
       // Read the next 4 valid bytes
       ToRead := 4;
       ReadOK := 0;
       while ToRead > 0 do begin
-        InputStream.Read(ReadBuf[ReadOK], ToRead);
-	i := ReadOk;
-	while i <= 3 do begin
-	  ReadBuf[i] := DecTable[ReadBuf[i]];
-	  if ReadBuf[i] = 99 then begin
-	    for j := i to 3 do
-	      ReadBuf[i] := ReadBuf[i + 1];
-	  end else begin
-	    Inc(i);
-	    Inc(ReadOK);
-	    Dec(ToRead);
+        OrgToRead := ToRead;
+        HaveRead := InputStream.Read(ReadBuf[ReadOK], ToRead);
+	//WriteLn('ToRead = ', ToRead, ', HaveRead = ', HaveRead, ', ReadOK=', ReadOk);
+	if HaveRead > 0 then begin
+	  i := ReadOk;
+	  while i <= HaveRead do begin
+	    ReadBuf[i] := DecTable[ReadBuf[i]];
+	    if ReadBuf[i] = 99 then
+	      for j := i to 3 do
+	        ReadBuf[i] := ReadBuf[i + 1]
+	    else begin
+	      Inc(i);
+	      Inc(ReadOK);
+	      Dec(ToRead);
+	    end;
 	  end;
 	end;
+	if HaveRead <> OrgToRead then begin
+	  //WriteLn('Ende? ReadOK=', ReadOK, ', count=', Count);
+	  for i := ReadOK to 3 do
+	    ReadBuf[i] := Ord('=');
+	  fEOF := True;
+	  if ReadOK < 2 then exit;    // Not enough data available in input stream
+	  break;
+	end;
+      end;
+
+      // Check for fill bytes
+      if (Count >= 2) and (ReadBuf[3] = Ord('=')) then begin
+        //WriteLn('Endemarkierung!');
+	fEOF := True;
+	if ReadBuf[2] = Ord('=') then
+	  Count := 1
+	else
+	  Count := 2;
       end;
+
+      // Decode the 4 bytes in the buffer to 3 undecoded bytes
       Buf[0] := ReadBuf[0] shl 2 or ReadBuf[1] shr 4;
       Buf[1] := (ReadBuf[1] and 15) shl 4 or ReadBuf[2] shr 2;
       Buf[2] := (ReadBuf[2] and 3) shl 6 or ReadBuf[3];
@@ -219,6 +240,7 @@ begin
     Inc(BufPos);
     Inc(CurPos);
     Dec(Count);
+    Inc(Result);
   end;
 end;
 
@@ -228,12 +250,31 @@ begin
 end;
 
 function TBase64DecodingStream.Seek(Offset: Longint; Origin: Word): Longint;
+var
+  ipos: LongInt;
+  endbytes: array[0..1] of Char;
 begin
+  {This will work only if the input stream supports seeking / Size. If not, the
+   input stream will raise an exception; we don't handle them here but pass them
+   to the caller.}
+  if InputStreamSize = -1 then begin
+    ipos := InputStream.Position;
+    InputStreamSize := ((InputStream.Size - ipos + 3) div 4) * 3;
+    InputStream.Seek(-2, soFromEnd);
+    InputStream.Read(endbytes, 2);
+    InputStream.Position := ipos;
+    if endbytes[1] = '=' then begin
+      Dec(InputStreamSize);
+    if endbytes[0] = '=' then
+      Dec(InputStreamSize);
+    end;
+  end;
+
   // This stream only supports the Seek modes needed for determining its size
   if (Origin = soFromCurrent) and (Offset = 0) then
     Result := CurPos
   else if (Origin = soFromEnd) and (Offset = 0) then
-    Result := DataLen
+    Result := InputStreamSize
   else if (Origin = soFromBeginning) and (Offset = CurPos) then
     Result := CurPos
   else
@@ -246,7 +287,10 @@ end.
 
 {
   $Log$
-  Revision 1.2  1999-08-09 16:12:28  michael
+  Revision 1.3  1999-08-13 16:31:41  michael
+  + Patch to support sizeless streams by Sebastian Guenter
+
+  Revision 1.2  1999/08/09 16:12:28  michael
   * Fixes and new examples from Sebastian Guenther
 
   Revision 1.1  1999/08/03 17:02:38  michael

+ 1 - 1
fcl/tests/README

@@ -31,4 +31,4 @@ tidea.pp     test program for IDEA encryption/decryption streams (MVC)
 b64test.pp   test program for base64 encoding streams (SG)
 b64test2.pp  test program for base64 encoding streams (SG)
 b64enc.pp    base64-encodes StdIn to StdOut (SG)
-b64dec.pp    base64-decodes file given as 1st argument to StdOut (SG)
+b64dec.pp    base64-decodes StdIn to StdOut (SG)

+ 7 - 3
fcl/tests/b64dec.pp

@@ -1,6 +1,6 @@
 // $Id$
 
-// base64-decodes a file (argument #1) and writes the output to StdOut
+// base64-decodes data from StdIn and writes the output to StdOut
 // (c) 1999 Sebastian Guenther
 
 {$MODE objfpc}
@@ -13,10 +13,11 @@ var
   IsEnd: Boolean;
 begin
 
-  InputStream := TFileStream.Create(ParamStr(1), fmOpenRead);
+  InputStream := THandleStream.Create(StdInputHandle);
 
   b64decoder := TBase64DecodingStream.Create(InputStream);
 
+  IsEnd := False;
   while not IsEnd do
     try
       Write(Chr(b64decoder.ReadByte));
@@ -31,7 +32,10 @@ end.
 
 {
   $Log$
-  Revision 1.1  1999-08-09 16:12:26  michael
+  Revision 1.2  1999-08-13 16:31:43  michael
+  + Patch to support sizeless streams by Sebastian Guenter
+
+  Revision 1.1  1999/08/09 16:12:26  michael
   * Fixes and new examples from Sebastian Guenther
 
 }