Matthew Hipkin
Base64 encode/decode binary files with Lazarus
Download: https://sourceforge.net/projects/base64-binary/
FreePascal already comes with all the objects necessary to bas64 encode and decode binary files. All you need is to add the base64 unit to your uses clause.
To encode binary files you'll need to use the TBase64EncodingStream object.
procedure EncodeFile(inputfile: String; outputfile: String); var fi,fo: TFileStream; enc: TBase64EncodingStream; newof: String; begin if Length(outputfile) < 1 then begin if Length(ExtractFileExt(inputfile)) > 0 then newof := AnsiReplaceStr(inputfile, ExtractFileExt(inputfile), '.txt') else newof := inputfile + '.txt'; end else newof := outputfile; write('Reading ',inputfile); fi := TFileStream.Create(inputfile,fmOpenRead); writeln('... Done'); write('Writing ',newof); fo := TFileStream.Create(newof,fmCreate); enc := TBase64EncodingStream.Create(fo); enc.CopyFrom(fi,fi.Size); enc.Free; writeln('... Done'); fo.Free; fi.Free; end;
We firstly read our input file into a standard TFileStream, pass it to the TBase64EncodingStream which automatically puts the encoded data into the specified output stream, which in this case is another TFileStream.
Decoding is achieved in a similar way.
procedure DecodeFile(inputfile: String; outputfile: String); var fo: TFileStream; enc: TBase64DecodingStream; s: TStringStream; F: TextFile; si: String; begin fo := TFileStream.Create(outputfile,fmCreate); write('Reading ',inputfile); AssignFile(F,inputfile); Reset(F); Read(F,si); CloseFile(F); writeln('... Done'); s := TStringStream.Create(si); write('Writing ',outputfile); enc := TBase64DecodingStream.Create(s); fo.CopyFrom(enc,enc.Size); enc.Free; writeln('... Done'); fo.Free; end;
This time, we load our encoded file into a TStringStream, pass that to a TBase64DecodingStream which automatically puts it into the output stream which once again is a TFileStream.
If you're developing a GUI application using Lazarus and want to display a progress bar, instead of copying the whole stream in a single CopyFrom() call you can split it into chunks. An example of this could be:
procedure TfrmMain.EncodeFile; const CHUNKSIZE = 524288; // Set a chunk size of 512k var fi: TFileStream; fo: TFileStream; enc: TBase64EncodingStream; begin // Setup streams fi := TFileStream.Create(textInputFile.FileName,fmOpenRead); fo := TFileStream.Create(textOutputFile.FileName,fmCreate or fmOpenWrite); enc := TBase64EncodingStream.Create(fo); // Reset input file stream position fi.Position := 0; // Set progress bar max value to filesize of input ProgressBar1.Max := FileSize(textInputFile.FileName); { Read the stream, looping in increments of CHUNKSIZE until stream is at an end } while fi.Position < fi.Size do begin if (fi.Position + CHUNKSIZE) < fi.Size then enc.CopyFrom(fi,CHUNKSIZE) else enc.CopyFrom(fi,fi.Size-fi.Position); // Set progress bar position ProgressBar1.Position := fi.Position; // Keep UI alive Application.ProcessMessages; end; enc.Free; fo.Free; fi.Free; end;
You can download my base64 encoder/decoder created with these function (both console and GUI) from here.
blog comments powered by Disqus