* Base64 en/de cdeing streams added

This commit is contained in:
michael 1999-08-03 17:02:36 +00:00
parent f429eb7622
commit b309bf03cc
5 changed files with 300 additions and 3 deletions

View File

@ -5,4 +5,4 @@ INCNAMES=classes.inc classesh.inc bits.inc collect.inc compon.inc filer.inc\
lists.inc parser.inc persist.inc reader.inc streams.inc stringl.inc\
writer.inc
INCUNITS=inifiles ezcgi pipes rtfpars idea
INCUNITS=inifiles ezcgi pipes rtfpars idea base64

258
fcl/inc/base64.pp Normal file
View File

@ -0,0 +1,258 @@
// $Id$
// Encoding and decoding streams for base64 data as described in RFC2045
{$MODE objfpc}
{$H+}
unit base64;
interface
uses classes;
type
TBase64EncodingStream = class(TStream)
protected
OutputStream: TStream;
TotalBytesProcessed, BytesWritten: LongWord;
Buf: array[0..2] of Byte;
BufSize: Integer; // # of bytes used in Buf
public
constructor Create(AOutputStream: TStream);
destructor Destroy; override;
function Read(var Buffer; Count: Longint): Longint; override;
function Write(const Buffer; Count: Longint): Longint; override;
function Seek(Offset: Longint; Origin: Word): Longint; override;
end;
TBase64DecodingStream = class(TStream)
protected
InputStream: TStream;
CurPos, DataLen: LongInt;
Buf: array[0..2] of Byte;
BufPos: Integer; // Offset of byte which is to be read next
public
constructor Create(AInputStream: TStream);
function Read(var Buffer; Count: Longint): Longint; override;
function Write(const Buffer; Count: Longint): Longint; override;
function Seek(Offset: Longint; Origin: Word): Longint; override;
end;
implementation
const
EncodingTable: PChar =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
DecTable: array[Byte] of Byte =
(99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, // 0-15
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, // 16-31
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 62, 99, 99, 99, 63, // 32-47
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 99, 99, 99, 00, 99, 99, // 48-63
99, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, // 64-79
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 99, 99, 99, 99, 99, // 80-95
99, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 99, 99, 99, 99, 99, // 112-127
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99);
constructor TBase64EncodingStream.Create(AOutputStream: TStream);
begin
inherited Create;
OutputStream := AOutputStream;
end;
destructor TBase64EncodingStream.Destroy;
var
WriteBuf: array[0..3] of Char;
begin
// Fill output to multiple of 3
case (TotalBytesProcessed mod 3) of
1: begin
WriteBuf[0] := EncodingTable[Buf[0] shr 2];
WriteBuf[1] := EncodingTable[(Buf[0] and 3) shl 4];
WriteBuf[2] := '=';
WriteBuf[3] := '=';
OutputStream.Write(WriteBuf, 4);
end;
2: begin
WriteBuf[0] := EncodingTable[Buf[0] shr 2];
WriteBuf[1] := EncodingTable[(Buf[0] and 3) shl 4 or (Buf[1] shr 4)];
WriteBuf[2] := EncodingTable[(Buf[1] and 15) shl 2];
WriteBuf[3] := '=';
OutputStream.Write(WriteBuf, 4);
end;
end;
inherited Destroy;
end;
function TBase64EncodingStream.Read(var Buffer; Count: Longint): Longint;
begin
raise EStreamError.Create('Invalid stream operation');
end;
function TBase64EncodingStream.Write(const Buffer; Count: Longint): Longint;
var
ReadNow: LongInt;
p: PChar;
WriteBuf: array[0..3] of Char;
begin
Inc(TotalBytesProcessed, Count);
Result := Count;
p := PChar(Buffer);
while count > 0 do begin
// Fetch data into the Buffer
ReadNow := 3 - BufSize;
if ReadNow > Count then break; // Not enough data available
Move(p, Buf[BufSize], ReadNow);
Inc(p, ReadNow);
Dec(Count, ReadNow);
// Encode the 3 bytes in Buf
WriteBuf[0] := EncodingTable[Buf[0] shr 2];
WriteBuf[1] := EncodingTable[(Buf[0] and 3) shl 4 or (Buf[1] shr 4)];
WriteBuf[2] := EncodingTable[(Buf[1] and 15) shl 2 or (Buf[2] shr 6)];
WriteBuf[3] := EncodingTable[Buf[2] and 63];
OutputStream.Write(WriteBuf, 4);
Inc(BytesWritten, 4);
BufSize := 0;
end;
Move(p, Buf[BufSize], count);
Inc(BufSize, count);
end;
function TBase64EncodingStream.Seek(Offset: Longint; Origin: Word): Longint;
begin
Result := BytesWritten;
if BufSize > 0 then
Inc(Result, 4);
// This stream only supports the Seek modes needed for determining its size
if not ((((Origin = soFromCurrent) or (Origin = soFromEnd)) and (Offset = 0))
or ((Origin = soFromBeginning) and (Offset = Result))) then
raise EStreamError.Create('Invalid stream operation');
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;
if endbytes[1] = '=' then begin
Dec(DataLen);
if endbytes[0] = '=' then
Dec(DataLen);
end;
// WriteLn('DataLen = ', DataLen);
end;
function TBase64DecodingStream.Read(var Buffer; Count: Longint): Longint;
var
p: PChar;
b: Char;
ReadBuf: array[0..3] of Byte;
ToRead, 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);
Result := Count;
p := PChar(@Buffer);
while Count > 0 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);
end;
end;
end;
// WriteLn('ReadBuf: ', ReadBuf[0], ' ', ReadBuf[1], ' ', ReadBuf[2], ' ', ReadBuf[3]);
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];
// WriteLn('Gelesen: ', Buf[0], ' ', Buf[1], ' ', Buf[2]);
end;
p[0] := Chr(Buf[BufPos]);
Inc(p);
Inc(BufPos);
Inc(CurPos);
Dec(Count);
end;
end;
function TBase64DecodingStream.Write(const Buffer; Count: Longint): Longint;
begin
raise EStreamError.Create('Invalid stream operation');
end;
function TBase64DecodingStream.Seek(Offset: Longint; Origin: Word): Longint;
begin
// 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
else if (Origin = soFromBeginning) and (Offset = CurPos) then
Result := CurPos
else
raise EStreamError.Create('Invalid stream operation');
end;
end.
{
$Log$
Revision 1.1 1999-08-03 17:02:38 michael
* Base64 en/de cdeing streams added
}
--------------596BB20743AE6B618A5C912C--)

View File

@ -36,7 +36,7 @@ NEEDOPT=-S2
UNITOBJECTS=
EXEOBJECTS=stringl dparser fstream mstream list threads testrtf\
cfgtest testz testz2 xmldump htdump testcgi tidea
cfgtest testz testz2 xmldump htdump testcgi tidea b64test
#####################################################################
@ -113,7 +113,10 @@ endif
#
# $Log$
# Revision 1.9 1999-07-25 14:30:39 michael
# Revision 1.10 1999-08-03 17:02:36 michael
# * Base64 en/de cdeing streams added
#
# Revision 1.9 1999/07/25 14:30:39 michael
# Initial implementation of encryption stream
#
# Revision 1.8 1999/07/15 12:05:55 michael

View File

@ -28,3 +28,4 @@ xmldump.pp xml dump program (SG)
htdump.pp htdump dumps XL IDL definition as ObjectPascal classes (MVC)
testcgi.pp test program for ezcgi class (MH)
tidea.pp test program for IDEA encryption/decryption streams (MVC)
b64test.pp test program for base64 encoding streams (SG)

35
fcl/tests/b64test.pp Normal file
View File

@ -0,0 +1,35 @@
{$MODE objfpc}
program b64test;
uses classes, base64, sysutils;
var
b64encoder: TBase64EncodingStream;
b64decoder: TBase64DecodingStream;
BaseStream: TStream;
i, j: Integer;
begin
BaseStream := TMemoryStream.Create;
WriteLn('Encoded Size / Decoded Size / Data:');
for i := 1 to 22 do begin
BaseStream.Position := 0;
b64encoder := TBase64EncodingStream.Create(BaseStream);
for j := 1 to i do
b64encoder.WriteByte(i - j + 65);
Write(b64encoder.Size: 2, ' ');
b64encoder.Free;
BaseStream.Position := 0;
b64decoder := TBase64DecodingStream.Create(BaseStream);
Write(b64decoder.Size: 2, ' ');
for j := 1 to i do
Write(Chr(b64decoder.ReadByte));
WriteLn;
b64decoder.Free;
end;
BaseStream.Free;
end.