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