How to identify a Base64-encoded string

In my current project I’ve created a Web Service-consumer in NAV that maps payload-data flexible using the Data Exchange Definition. Unfortunately in REST- and SOAP-payloads, binary information (JPG, PDF etc.)  is delivered as a string. So, I’ve got a little task to find a way to differ between a string (like an address line) and binary information.

As all REST- and SOAP-Web Services, the payload of the Web Service I’m using, delivers the payload as a structured, but simple text-file. This means, all data is delivered in Text-format. But to be able, for example, to store price-information in the database and use it in mathematical calculations, it is necessary to transform the value from Text to Decimal. My Web Service-consumer is able to read the payload, to identify and to transform the DataTypes automatically. But as soon as binary information will be delivered in the payload, my consumer reaches a limit because the binary information would be stored as Text.

Luckily, all binary information of a REST- or SOAP-service will be encoded in Base64-format, so it is an easy task to identify whether it’s a regular text-value (like a company name or delivery instructions) or binary-information. Encoded data will always have the following characteristic:

  • The length of a Base64-encoded string is always a multiple of 4
  • Only these characters are used by the encryption: “A” to “Z”, “a” to “z”, “0” to “9”, “+” and “/”
  • The end of a string can be padded up to two times using the “=”-character (this character is allowed in the end only)

Based on this information it was possible to build a function that is able to identify the value of a string as Base64-encoded.

LOCAL PROCEDURE [email protected]([email protected] : Variant) : Boolean;
VAR
 [email protected] : Integer;
BEGIN
 // the length of a base64 is always a multiple of 4
 // allowed characters in a base64 are: 'A'..'Z', 'a'..'z', '0'..'9', '+', '/'
 // the end can be padded with up to 2 '='

 // check if the length is a multiple of 4
 IF (STRLEN(FORMAT(pVariant,0,9)) / 4 MOD 1) <> 0 THEN
   EXIT(FALSE);

 // check each character if allowed
 FOR i := 1 TO STRLEN(FORMAT(pVariant,0,9)) DO
 IF NOT (COPYSTR(FORMAT(pVariant,0,9),i,1) IN ['A'..'Z', 'a'..'z', '0'..'9', '+', '/']) THEN
   BEGIN
   // if not allowed character found, check if already at end of string (and check for '=')
     IF (i = STRLEN(FORMAT(pVariant,0,9))-1) OR
        (i = STRLEN(FORMAT(pVariant,0,9)))
     THEN
       BEGIN
         IF COPYSTR(FORMAT(pVariant,0,9),i,1) <> '=' THEN
           EXIT(FALSE);
       END
     ELSE
       EXIT(FALSE);
     END;

   EXIT(TRUE);
END;

Additionally, I’ve created a function that decodes the Base64-string and stores it in a BLOB-field.

[TryFunction]
LOCAL PROCEDURE [email protected]([email protected] : Variant;VAR [email protected] : TEMPORARY Record 99008535);
VAR
 [email protected] : OutStream;
 [email protected] : DotNet "'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Convert";
 [email protected] : DotNet "'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.IO.MemoryStream";
BEGIN
 MemoryStream := MemoryStream.MemoryStream(Convert.FromBase64String(pVariant));
 pTempBLOB.Blob.CREATEOUTSTREAM(BlobWriter);
 MemoryStream.CopyTo(BlobWriter);
END;

I have compiled the two functions into a Codeunit (including an example) and published for download on mibuso.com.

Leave a Comment

Your email address will not be published. Required fields are marked *