Aziz Sirojiddinov
Aziz Sirojiddinov

Reputation: 89

How to check whether a string is base64 encoded or not?

I want to check HTML img src is in base64 encoded format or not in my java spring backend. if it is Base64 encoded then I will just decode image and save to my server if it is not I will download firstly based on image URL path then save to my server. I've built a downloading image and decoding image functions. But can't resolve the base64 check. I tried to use try catch checking statement but I do not need catching error if it is not base64. P.S I am using java.util.Base64

public boolean isBase64(String path) {
   try {
        Base64.getDecoder().decode(path);

    } catch(IllegalArgumentException e) {   
    }
}

Upvotes: 2

Views: 12049

Answers (4)

ROVIS EU
ROVIS EU

Reputation: 1

test Base64.getDecoder().decode(input) return true always... :-( try this (works for me):

private boolean testStringIsBase64(String input) {
  boolean result = false;
  String test;
  try {
    test = convertStringFromBase64(input);
    if (input.equals(convertStringToBase64(test))) {
      result = true;
    }
  }
  catch (Exception ex) {
    result = false;
  }
  return result;
}

private String convertStringToBase64(String input) {
  return Base64.getEncoder().encodeToString(input.getBytes());
}

private String convertStringFromBase64(String input) {
  return new String(Base64.getDecoder().decode(input));
}

whenever you try encode and back to decode and strings are same, input is Base64

R.

Upvotes: 0

Dave The Dane
Dave The Dane

Reputation: 869

I'm still not sure whether you're looking at URL's or want to inspect the data.
For the latter, you could do something like this...

/*
 * Some typical Image-File Signatures (starting @ byte 0)
 */
private static final byte[] JPG_1 = new byte[] {-1, -40, -1, -37};
private static final byte[] JPG_2 = new byte[] {-1, -40, -1, -18};
private static final byte[] PNG   = new byte[] {-119, 80, 78, 71, 13, 10, 26, 10};

public static boolean isMime(final InputStream ist) {
    /*
     * The number of bytes of Mime-encoded Data you want to read.
     * (4 * 19 = 76, which is MIMELINEMAX from Base64$Encoder)
     */
    final int    mimeBlockLength  =  4;  // <- MUST be 4!
    final int    mimeBlockCount   = 19;  // <- your choice
    final int    mimeBufferLength = mimeBlockCount * mimeBlockLength;

    final byte[] bar              = new byte[mimeBufferLength];

    try (final BufferedInputStream bis = new BufferedInputStream(ist, mimeBufferLength))
    {
        /*
         * We expect at least one complete Mime-encoded buffer...
         */
        if (bis.read(bar) != mimeBufferLength) {
            return false;
        }
        /*
         * Use a Java 9 feature to compare Signatures...
         */
        if (Arrays.equals(bar, 0, JPG_1.length, JPG_1, 0, JPG_1.length)
        ||  Arrays.equals(bar, 0, JPG_2.length, JPG_2, 0, JPG_2.length)
        ||  Arrays.equals(bar, 0, PNG  .length, PNG  , 0, PNG  .length)) {
            return true;
        } else {
            return false;
        }
    } catch (final IOException e) {
        return false;
    }
}

Upvotes: 0

edwgiz
edwgiz

Reputation: 862

If you receive the exact value by <img src="..." /> attribute then it should have Data URL format

The simple regexp could determine whether the URL is Data or regular. In java it can look like

    private static final Pattern DATA_URL_PATTERN = Pattern.compile("^data:image/(.+?);base64,\\s*", Pattern.CASE_INSENSITIVE);

    static void handleImgSrc(String path) {
        if (path.startsWith("data:")) {
            final Matcher m = DATA_URL_PATTERN.matcher(path);
            if (m.find()) {
                String imageType = m.group(1);
                String base64 = path.substring(m.end());
                // decodeImage(imageType, base64);
            } else {
                // some logging
            }
        } else {
            // downloadImage(path);
        }
    }

Upvotes: 1

Robert
Robert

Reputation: 42585

Theoretically you can't decide if some string is base64 decoded or not, because by chance any regular string may be base64 decodable.

In reality however for longer data the chance is low that it is base64 decodeable but not a base64 encoded data.

In general I don't see a problem in your approach, your method just need some small improvements:

public boolean isBase64(String path) {
   try {
        Base64.getDecoder().decode(path);
        return true;
    } catch(IllegalArgumentException e) {   
        return false;
    }
}

In my opinion this approach is very inefficient because if the data is base64 decodable I assume you want the base64 decoded data. Therefore in such a case you are performing the base64 decoding twice (one time for checking isBase64 and one time for the actual encoding). Therefore I would use something like this:

public byte[] tryDecodeBase64(String path) {
   try {
        return Base64.getDecoder().decode(path);
    } catch(IllegalArgumentException e) {   
        return null;
    }
}

Upvotes: 1

Related Questions