3131import java .io .IOException ;
3232import java .io .InputStream ;
3333import java .lang .reflect .Field ;
34+ import java .lang .reflect .InvocationTargetException ;
35+ import java .lang .reflect .Method ;
3436import java .lang .reflect .Modifier ;
3537import java .math .BigInteger ;
3638import java .nio .ByteBuffer ;
39+ import java .nio .charset .StandardCharsets ;
3740import java .security .Permission ;
3841import java .security .PermissionCollection ;
3942import java .util .*;
@@ -45,6 +48,8 @@ public final class Utils {
4548 private final static char [] hexArray = "0123456789ABCDEF" .toCharArray ();
4649 private static final Logger LOGGER = LoggerFactory .getLogger (Utils .class );
4750 private static final String randomString = "abcdefghijklmnopqrstuvwxyz0123456789" ;
51+ private static final String JAVA_UTIL_BASE_64 = "java.util.Base64" ;
52+ private static final String ANDROID_UTIL_BASE_64 = "android.util.Base64" ;
4853
4954 private Utils () {
5055 }
@@ -310,12 +315,70 @@ public static String artistsToString(List<Metadata.Artist> artists) {
310315 }
311316
312317 @ NotNull
313- public static String toBase64 (@ NotNull ByteString bytes ) {
314- return Base64 .getEncoder ().encodeToString (bytes .toByteArray ());
318+ public static String toBase64 (@ NotNull byte [] bytes , boolean padding ) {
319+ byte [] encodedBytes ;
320+ try {
321+ Class <?> clazz = Class .forName (JAVA_UTIL_BASE_64 );
322+ final Method getEncoder = clazz .getDeclaredMethod ("getEncoder" );
323+ Class <?> encoderClazz = Class .forName ("java.util.Base64$Encoder" );
324+ Object encoder = getEncoder .invoke (null );
325+ final Method withoutPadding = encoderClazz .getDeclaredMethod ("withoutPadding" );
326+ if (!padding )
327+ encoder = withoutPadding .invoke (encoder );
328+ final Method encode = encoderClazz .getDeclaredMethod ("encode" , byte [].class );
329+ encodedBytes = (byte []) encode .invoke (encoder , bytes );
330+ } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored ) {
331+ try {
332+ Class <?> clazz = Class .forName (ANDROID_UTIL_BASE_64 );
333+ final Method encode = clazz .getDeclaredMethod ("encode" , byte [].class , int .class );
334+ int flags = 2 ; // Base64.NO_WRAP
335+ if (!padding )
336+ flags |= 1 ; // Base64.NO_PADDING
337+ encodedBytes = (byte []) encode .invoke (null , bytes , flags ); // Base64.NO_WRAP | Base64.NO_PADDING
338+ } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored2 ) {
339+ throw new NoClassDefFoundError ("Base64 not available" );
340+ }
341+ }
342+
343+ return new String (encodedBytes , StandardCharsets .UTF_8 );
315344 }
316345
317346 @ NotNull
318- public static ByteString fromBase64 (@ NotNull String str ) {
319- return ByteString .copyFrom (Base64 .getDecoder ().decode (str .getBytes ()));
347+ public static String toBase64NoPadding (@ NotNull byte [] bytes ) {
348+ return toBase64 (bytes , false );
349+ }
350+
351+ @ NotNull
352+ public static String toBase64 (@ NotNull byte [] bytes ) {
353+ return toBase64 (bytes , true );
354+ }
355+
356+ @ NotNull
357+ public static byte [] fromBase64 (@ NotNull String str ) {
358+ return fromBase64 (str .getBytes ());
359+ }
360+
361+ @ NotNull
362+ public static byte [] fromBase64 (@ NotNull byte [] bytes ) {
363+ byte [] decodedBytes ;
364+ try {
365+ Class <?> clazz = Class .forName (JAVA_UTIL_BASE_64 );
366+ final Method getDecoder = clazz .getDeclaredMethod ("getDecoder" );
367+ final Object decoder = getDecoder .invoke (null );
368+ Class <?> decoderClazz = Class .forName ("java.util.Base64$Decoder" );
369+ final Method decode = decoderClazz .getDeclaredMethod ("decode" , byte [].class );
370+ decodedBytes = (byte []) decode .invoke (decoder , bytes );
371+ } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored ) {
372+ try {
373+ Class <?> clazz = Class .forName (ANDROID_UTIL_BASE_64 );
374+ final Method decode = clazz .getDeclaredMethod ("decode" , byte [].class , int .class );
375+ int flags = 0 ; // android.util.Base64.DEFAULT
376+ decodedBytes = (byte []) decode .invoke (null , bytes , flags );
377+ } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored2 ) {
378+ throw new NoClassDefFoundError ("Base64 not available" );
379+ }
380+ }
381+
382+ return decodedBytes ;
320383 }
321384}
0 commit comments