Search code examples
javaandroiddelphifiremonkey

Convert JInputStream to Base64


I convert a JInputStream to base64 with a MemoryStream as intermediary. I need to do that because JInputStream doesn't extend the base class TStream.

I deliberately simplified the code by removing the try/finally block.

JStream := TAndroidHelper.ContentResolver.openInputStream(StrToJURI(FSelector.Files[I]));
Buffer := TJavaArray<Byte>.Create(JStream.Available);
JStream.Read(Buffer);

MStream := TMemoryStream.Create;
MStream.Write(Buffer.Data^, Buffer.Length);
MStream.position := 0;

SStream := TStringStream.Create('', TEncoding.ASCII);
Soap.EncdDecd.EncodeStream(MStream, SStream);
Base64Stream := SStream.DataString;
Base64Stream := Base64Stream.Replace(#10, '');
Base64Stream := Base64Stream.Replace(#13, '');

Does a method exist to directly convert the data of my JInputSream to base64?


Solution

  • Import for the Android Base64 class:

    uses
      Androidapi.JNIBridge, Androidapi.JNI.JavaTypes;
    
    type
      JBase64Class = interface(JObjectClass)
        ['{DA78E162-4CB0-455B-ACC0-BEDDE5484C85}']
        function _GetCRLF: Integer; cdecl;
        function _GetDEFAULT: Integer; cdecl;
        function _GetNO_CLOSE: Integer; cdecl;
        function _GetNO_PADDING: Integer; cdecl;
        function _GetNO_WRAP: Integer; cdecl;
        function _GetURL_SAFE: Integer; cdecl;
        function decode(input: TJavaArray<Byte>; flags: Integer): TJavaArray<Byte>; cdecl; overload;
        function decode(input: TJavaArray<Byte>; offset: Integer; len: Integer; flags: Integer): TJavaArray<Byte>; cdecl; overload;
        function decode(str: JString; flags: Integer): TJavaArray<Byte>; cdecl; overload;
        function encode(input: TJavaArray<Byte>; flags: Integer): TJavaArray<Byte>; cdecl; overload;
        function encode(input: TJavaArray<Byte>; offset: Integer; len: Integer; flags: Integer): TJavaArray<Byte>; cdecl; overload;
        function encodeToString(input: TJavaArray<Byte>; flags: Integer): JString; cdecl; overload;
        function encodeToString(input: TJavaArray<Byte>; offset: Integer; len: Integer; flags: Integer): JString; cdecl; overload;
        property &DEFAULT: Integer read _GetDEFAULT;
        property CRLF: Integer read _GetCRLF;
        property NO_CLOSE: Integer read _GetNO_CLOSE;
        property NO_PADDING: Integer read _GetNO_PADDING;
        property NO_WRAP: Integer read _GetNO_WRAP;
        property URL_SAFE: Integer read _GetURL_SAFE;
      end;
    
      [JavaSignature('android/util/Base64')]
      JBase64 = interface(JObject)
        ['{AC976256-7237-4F07-87CD-B57F5F28BF6A}']
      end;
      TJBase64 = class(TJavaGenericImport<JBase64Class, JBase64>)
      end;
    

    Function to encode the file-based URI into Base64:

    uses
      System.SysUtils,
      Androidapi.Helpers, Androidapi.JNI.Net, Androidapi.JNI.JavaTypes;
    
    function JURIToBase64(const AJURI: Jnet_Uri): string;
    var
      LInput: JInputStream;
      LJavaBytes: TJavaArray<Byte>;
      LBytes: TBytes;
    begin
      LInput := TAndroidHelper.Context.getContentResolver.openInputStream(AJURI);
      LJavaBytes := TJavaArray<Byte>.Create(LInput.available);
      try
        LInput.read(LJavaBytes, 0, LJavaBytes.Length);
        Result := JStringToString(TJBase64.JavaClass.encodeToString(LJavaBytes, TJBase64.JavaClass.NO_WRAP));
      finally
        LJavaBytes.Free;
      end;
    end;
    

    Example usage based on your requirements:

    Base64Result := JURIToBase64(StrToJURI(FSelector.Files[I]));