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)
   TBase64DecodingStream = class(TStream)
   protected
   protected
     InputStream: TStream;
     InputStream: TStream;
-    CurPos, DataLen: LongInt;
+    CurPos, InputStreamSize: LongInt;
     Buf: array[0..2] of Byte;
     Buf: array[0..2] of Byte;
     BufPos: Integer;    // Offset of byte which is to be read next
     BufPos: Integer;    // Offset of byte which is to be read next
+    fEOF: Boolean;
   public
   public
     constructor Create(AInputStream: TStream);
     constructor Create(AInputStream: TStream);
+    procedure Reset;
 
 
     function Read(var Buffer; Count: Longint): Longint; override;
     function Read(var Buffer; Count: Longint): Longint; override;
     function Write(const Buffer; Count: Longint): Longint; override;
     function Write(const Buffer; Count: Longint): Longint; override;
     function Seek(Offset: Longint; Origin: Word): Longint; override;
     function Seek(Offset: Longint; Origin: Word): Longint; override;
+    property EOF: Boolean read fEOF;
   end;
   end;
 
 
 
 
@@ -153,25 +156,17 @@ end;
 
 
 
 
 constructor TBase64DecodingStream.Create(AInputStream: TStream);
 constructor TBase64DecodingStream.Create(AInputStream: TStream);
-var
-  ipos: LongInt;
-  endbytes: array[0..1] of Char;
 begin
 begin
   inherited Create;
   inherited Create;
   InputStream := AInputStream;
   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;
 end;
 
 
 function TBase64DecodingStream.Read(var Buffer; Count: Longint): Longint;
 function TBase64DecodingStream.Read(var Buffer; Count: Longint): Longint;
@@ -179,36 +174,62 @@ var
   p: PChar;
   p: PChar;
   b: Char;
   b: Char;
   ReadBuf: array[0..3] of Byte;
   ReadBuf: array[0..3] of Byte;
-  ToRead, ReadOK, i, j: Integer;
+  ToRead, OrgToRead, HaveRead, ReadOK, i, j: Integer;
 begin
 begin
   if Count <= 0 then exit(0);
   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);
   p := PChar(@Buffer);
-  while Count > 0 do begin
+  while (Count > 0) and not fEOF do begin
     if BufPos > 2 then begin
     if BufPos > 2 then begin
       BufPos := 0;
       BufPos := 0;
       // Read the next 4 valid bytes
       // Read the next 4 valid bytes
       ToRead := 4;
       ToRead := 4;
       ReadOK := 0;
       ReadOK := 0;
       while ToRead > 0 do begin
       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;
 	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;
       end;
+
+      // Decode the 4 bytes in the buffer to 3 undecoded bytes
       Buf[0] := ReadBuf[0] shl 2 or ReadBuf[1] shr 4;
       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[1] := (ReadBuf[1] and 15) shl 4 or ReadBuf[2] shr 2;
       Buf[2] := (ReadBuf[2] and 3) shl 6 or ReadBuf[3];
       Buf[2] := (ReadBuf[2] and 3) shl 6 or ReadBuf[3];
@@ -219,6 +240,7 @@ begin
     Inc(BufPos);
     Inc(BufPos);
     Inc(CurPos);
     Inc(CurPos);
     Dec(Count);
     Dec(Count);
+    Inc(Result);
   end;
   end;
 end;
 end;
 
 
@@ -228,12 +250,31 @@ begin
 end;
 end;
 
 
 function TBase64DecodingStream.Seek(Offset: Longint; Origin: Word): Longint;
 function TBase64DecodingStream.Seek(Offset: Longint; Origin: Word): Longint;
+var
+  ipos: LongInt;
+  endbytes: array[0..1] of Char;
 begin
 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
   // This stream only supports the Seek modes needed for determining its size
   if (Origin = soFromCurrent) and (Offset = 0) then
   if (Origin = soFromCurrent) and (Offset = 0) then
     Result := CurPos
     Result := CurPos
   else if (Origin = soFromEnd) and (Offset = 0) then
   else if (Origin = soFromEnd) and (Offset = 0) then
-    Result := DataLen
+    Result := InputStreamSize
   else if (Origin = soFromBeginning) and (Offset = CurPos) then
   else if (Origin = soFromBeginning) and (Offset = CurPos) then
     Result := CurPos
     Result := CurPos
   else
   else
@@ -246,7 +287,10 @@ end.
 
 
 {
 {
   $Log$
   $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
   * Fixes and new examples from Sebastian Guenther
 
 
   Revision 1.1  1999/08/03 17:02:38  michael
   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)
 b64test.pp   test program for base64 encoding streams (SG)
 b64test2.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)
 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$
 // $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
 // (c) 1999 Sebastian Guenther
 
 
 {$MODE objfpc}
 {$MODE objfpc}
@@ -13,10 +13,11 @@ var
   IsEnd: Boolean;
   IsEnd: Boolean;
 begin
 begin
 
 
-  InputStream := TFileStream.Create(ParamStr(1), fmOpenRead);
+  InputStream := THandleStream.Create(StdInputHandle);
 
 
   b64decoder := TBase64DecodingStream.Create(InputStream);
   b64decoder := TBase64DecodingStream.Create(InputStream);
 
 
+  IsEnd := False;
   while not IsEnd do
   while not IsEnd do
     try
     try
       Write(Chr(b64decoder.ReadByte));
       Write(Chr(b64decoder.ReadByte));
@@ -31,7 +32,10 @@ end.
 
 
 {
 {
   $Log$
   $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
   * Fixes and new examples from Sebastian Guenther
 
 
 }
 }