2
0
Эх сурвалжийг харах

* Base64 en/de cdeing streams added

michael 26 жил өмнө
parent
commit
b309bf03cc

+ 1 - 1
fcl/inc/Makefile.inc

@@ -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\
          lists.inc parser.inc persist.inc reader.inc streams.inc stringl.inc\
          writer.inc
          writer.inc
 
 
-INCUNITS=inifiles ezcgi pipes rtfpars idea
+INCUNITS=inifiles ezcgi pipes rtfpars idea base64

+ 258 - 0
fcl/inc/base64.pp

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

+ 5 - 2
fcl/tests/Makefile

@@ -36,7 +36,7 @@ NEEDOPT=-S2
 
 
 UNITOBJECTS=
 UNITOBJECTS=
 EXEOBJECTS=stringl dparser fstream mstream list threads testrtf\
 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$
 # $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
 # Initial implementation of encryption stream
 #
 #
 # Revision 1.8  1999/07/15 12:05:55  michael
 # Revision 1.8  1999/07/15 12:05:55  michael

+ 1 - 0
fcl/tests/README

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

+ 35 - 0
fcl/tests/b64test.pp

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