+ Patch to support sizeless streams by Sebastian Guenter

This commit is contained in:
michael 1999-08-13 16:31:41 +00:00
parent 54baf96873
commit 4f4354e276
3 changed files with 87 additions and 39 deletions

View File

@ -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;
Reset;
end;
procedure TBase64DecodingStream.Reset;
begin
InputStreamSize := -1;
BufPos := 3; BufPos := 3;
fEOF := False;
ipos := InputStream.Position;
DataLen := ((InputStream.Size - ipos + 3) div 4) * 3;
InputStream.Seek(-2, soFromEnd);
InputStream.Read(endbytes, 2);
InputStream.Position := ipos;
if endbytes[1] = '=' then begin
Dec(DataLen);
if endbytes[0] = '=' then
Dec(DataLen);
end;
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 if InputStreamSize <> -1 then begin
Count := DataLen - CurPos; if CurPos + Count > InputStreamSize then
Count := InputStreamSize - CurPos;
if Count <= 0 then exit(0); 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); OrgToRead := ToRead;
HaveRead := InputStream.Read(ReadBuf[ReadOK], ToRead);
//WriteLn('ToRead = ', ToRead, ', HaveRead = ', HaveRead, ', ReadOK=', ReadOk);
if HaveRead > 0 then begin
i := ReadOk; i := ReadOk;
while i <= 3 do begin while i <= HaveRead do begin
ReadBuf[i] := DecTable[ReadBuf[i]]; ReadBuf[i] := DecTable[ReadBuf[i]];
if ReadBuf[i] = 99 then begin if ReadBuf[i] = 99 then
for j := i to 3 do for j := i to 3 do
ReadBuf[i] := ReadBuf[i + 1]; ReadBuf[i] := ReadBuf[i + 1]
end else begin else begin
Inc(i); Inc(i);
Inc(ReadOK); Inc(ReadOK);
Dec(ToRead); Dec(ToRead);
end; 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;
// 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

View File

@ -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)

View File

@ -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
} }