Encode base64 and Decode base64 using delphi 2007

31,332

Solution 1

Indy ships with Delphi, and has TIdEncoderMIME and TIdDecoderMIME classes for handling base64. For example:

uses
  ..., IdCoder, IdCoderMIME;

var
  Bytes: TIdBytes;
  Base64String: String;
begin
  //...
  Bytes := ...; // array of bytes
  //...
  Base64String := TIdEncoderMIME.EncodeBytes(Bytes);
  //...
  Bytes := TIdDecoderMIME.DecodeBytes(Base64String);
  //...
end;

There are also methods for encoding/decoding String and TStream data as well.

Update: alternatively, if your version does not have the class methods shown above:

// TBytesStream was added in D2009, so define it manually for D2007

uses
  ..., IdCoder, IdCoderMIME
  {$IF RTLVersion < 20)
  , RTLConsts
  {$IFEND}
  ;

{$IF RTLVersion < 20)
type
  TBytesStream = class(TMemoryStream)
  private
    FBytes: TBytes;
  protected
    function Realloc(var NewCapacity: Longint): Pointer; override;
  public
    constructor Create(const ABytes: TBytes); overload;
    property Bytes: TBytes read FBytes;
  end;

constructor TBytesStream.Create(const ABytes: TBytes);
begin
  inherited Create;
  FBytes := ABytes;
  SetPointer(Pointer(FBytes), Length(FBytes));
  FCapacity := FSize;
end;

const
  MemoryDelta = $2000; // Must be a power of 2

function TBytesStream.Realloc(var NewCapacity: Integer): Pointer;
begin
  if (NewCapacity > 0) and (NewCapacity <> FSize) then
    NewCapacity := (NewCapacity + (MemoryDelta - 1)) and not (MemoryDelta - 1);
  Result := Pointer(FBytes);
  if NewCapacity <> FCapacity then
  begin
    SetLength(FBytes, NewCapacity);
    Result := Pointer(FBytes);
    if NewCapacity = 0 then
      Exit;
    if Result = nil then raise EStreamError.CreateRes(@SMemoryStreamError);
  end;
end;
{$IFEND}

var
  Bytes: TBytes;
  BStrm: TBytesStream;
  Encoder: TIdEncoderMIME;
  Decoder: TIdDecoderMIME;
  Base64String: String;
begin
  //...
  Bytes := ...; // array of bytes
  //...
  BStrm := TBytesStream.Create(Bytes);
  try
    Encoder := TIdEncoderMIME.Create;
    try
      Base64String := Encoder.Encode(BStrm);
    finally
      Encoder.Free;
    end;
  finally
    BStrm.Free;
  end;
  //...
  BStrm := TBytesStream.Create;
  try
    Decoder := TIdDecoderMIME.Create;
    try
      Decoder.DecodeBegin(BStrm);
      Decoder.Decode(Base64String);
      Decoder.DecodeEnd;
    finally
      Decoder.Free;
    end;
    Bytes := BStrm.Bytes;
  finally
    BStrm.Free;
  end;
  //...
end;

Solution 2

Contrary to what you state in the question, the EncdDecd unit is included in Delphi 2007. You can simply use that.

Solution 3

David Heffernan responded very well!

Add in your uses the class "EncdDecd", it will have the procedures:

function DecodeString (const Input: string): string;
function DecodeBase64 (const Input: string): TBytes;

Testing with https://www.base64encode.org/

The String "Working" in both Delphi and the site resulted in: "V29ya2luZw =="

ShowMessage ('Working =' + EncodeString ('Working'));
ShowMessage ('Working =' + DecodeString ('V29ya2luZw =='));

Solution 4

For OLDER versions of Delphi (before of Delphi XE7), use:

uses 
Soap.EncdDecd
procedure DecodeFile(const Base64: AnsiString; const FileName: string);
var
  BStream: TBytesStream;
begin
  BStream := TBytesStream.Create(DecodeBase64(Base64));
  try
    BStream.SaveToFile(Filename);
  finally
    BStream.Free;
  end;
end;

For NEWS versions of Delphi, use:

uses
System.NetEncoding;
procedure DecodeFile(const Base64: String; const FileName: string);
var
  BStream: TBytesStream;
begin
  BStream:= TBytesStream.Create(TNetEncoding.Base64.DecodeStringToBytes(Base64));
  try
    BStream.SaveToFile(Filename);
  finally
    BStream.Free;
  end;
end;

Solution 5

Here goes EncodeToBase64:

uses
classes, sysutils;

function EncodeToBase64(var Buffer: TBytes): Longint;
const
  EncodingTable: PChar = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var
  WriteBuf: array[0..3] of Byte;
  Buf: array[0..2] of Byte;
  Dest: TMemoryStream;
  i, j, Count: Integer;
begin
  Result := 0;

  Count := Length(Buffer);
  j := Count div 3;

  if j > 0 then
  begin
    Dest:= TMemoryStream.Create();  
    try
      Dest.Position := 0;
      for i := 0 to j - 1  do
      begin
        Move(Buffer[i * 3], Buf[0], 3); 
        WriteBuf[0] := Ord(EncodingTable[Buf[0] shr 2]);
        WriteBuf[1] := Ord(EncodingTable[(Buf[0] and 3) shl 4 or (Buf[1] shr 4)]);
        WriteBuf[2] := Ord(EncodingTable[(Buf[1] and 15) shl 2 or (Buf[2] shr 6)]);
        WriteBuf[3] := Ord(EncodingTable[Buf[2] and 63]);  
        Dest.Write(WriteBuf, 4);  
        Inc(Result, 4);
        Dec(Count, 3);    
      end;          

      if Count in [1, 2] then  
      begin           
        Move(Buffer[i * 3], Buf[0], Count);
        WriteBuf[0] := Ord(EncodingTable[Buf[0] shr 2]);
        WriteBuf[1] := Ord(EncodingTable[(Buf[0] and 3) shl 4 or (Buf[1] shr 4)]); 
        if Count = 1 then
          WriteBuf[2] := Ord('=')
        else                                           
          WriteBuf[2] := Ord(EncodingTable[(Buf[1] and 15) shl 2 or (Buf[2] shr 6)]);
        WriteBuf[3] := Ord('='); 
        Dest.Write(WriteBuf, 4);  
        Inc(Result, 4);
        Dec(Count, Count);
      end;

      if Result > 0 then
      begin
        SetLength(Buffer, Result);
        Dest.Position := 0;
        Dest.Read(Buffer[0], Result);   
      end;  
    finally
      Dest.Free;
    end;
  end;

end; 

And this should work without any special units or components.

Share:
31,332
Hwau
Author by

Hwau

Updated on July 09, 2022

Comments

  • Hwau
    Hwau almost 2 years

    I have to encode an array of bytes to a base64 string (and decode this string) on an old Delphi 2007. How could I do?

    Further Informations:

    I've tried synapse (As suggested here Binary to Base64 (Delphi)).

  • Hwau
    Hwau almost 9 years
    It works good on further delphi version! Thanks for your suggestion and sample, I'll check this on Delphi 2007 as soon as possible, but I suppose it also works on old ide.
  • whosrdaddy
    whosrdaddy almost 9 years
    @Hwau: you can upgrade Indy to the latest version, even on older Delphi's
  • Hwau
    Hwau almost 9 years
    Unfortunately, EncodeBytes and DecodeBytes functions are undeclared using Delphi2007. I would prefer to don't upgrade indy manually, is there another way?
  • Remy Lebeau
    Remy Lebeau almost 9 years
    @Hwau: You will have to look in D2007's IdCoder unit and see what functions are actually available in that version. Worse case, the class methods might not be available, so try instantiating TIdEncoderMIME/TIdDecoderMIME objects and use their non-class methods instead. I updated my answer with an example.
  • Hwau
    Hwau almost 9 years
    @RemyLebeau: I'm sorry for long silence, TBytesStream seems to be undefined in Delphi-2007, how else could I load bytes array into stream?
  • Remy Lebeau
    Remy Lebeau almost 9 years
    TBytesStream was added in D2009. I have updated my answer to include an implementation for D2007. Or, you could simply copy the bytes into a standard TMemoryStream.