Showing posts with label base64. Show all posts
Showing posts with label base64. Show all posts

Friday, September 20, 2013

MarkLogic base64 encoding of a binary file using MLJAM

MarkLogic has the function xdmp:base64-encode, which unfortunately only works on xs:string's.

I needed a function to convert an arbitrary file (ie. binary) into a base64 encoded stream in order to put it into an atom+xml http post to feed Alfresco document management system.  Luckily I found MLJAM, which allows you to embed Java into xquery.  I found the needed Java snippet here, and then put it together - the code below should work in the MarkLogic Query console, just set the filename parameter accordingly.

Ultimately MarkLogic should have xdmp:base64-encode work on a binary node, then you could simply do xdmp:base64-encode(xdmp:external-binary("/some/path/image.png"))!

xquery version "1.0-ml";
import module namespace jam = "http://xqdev.com/jam" at "/MarkLogic/jam.xqy";
let $code := <code><![CDATA[
import org.apache.commons.codec.binary.Base64;
private String encodeFileToBase64Binary(String fileName)
throws IOException {
File file = new File(fileName);
byte[] bytes = loadFile(file);
byte[] encoded = Base64.encodeBase64(bytes);
String encodedString = new String(encoded);
return encodedString;
}
 
private static byte[] loadFile(File file) throws IOException {
   InputStream is = new FileInputStream(file);
     long length = file.length();
   if (length > Integer.MAX_VALUE) {
       // File is too large
   }
   byte[] bytes = new byte[(int)length];
   
   int offset = 0;
   int numRead = 0;
   while (offset < bytes.length
          && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
       offset += numRead;
   }
 
   if (offset < bytes.length) {
       throw new IOException("Could not completely read file "+file.getName());
   }
 
   is.close();
   return bytes;
}
  
    return encodeFileToBase64Binary(filename);
]]></code>
  
let $path := "http://localhost:8080/mljam/mljam"
let $connect := jam:start($path, (), ())
let $vars := jam:set("filename", "/some/path/image.png")
let $eval := jam:eval-get($code)
let $end := jam:end()
return $eval

Wednesday, September 12, 2012

MarkLogic xdmp:email with binary attachments need wrapping

According to RFC 2045, MIME base64 encoded attachments need to be wrapped at 76 characters.

Most email clients can handle attachments that are not wrapped (meaning the base64 encoding is not wrapped at 76 charaters), but some, specifically MS Outlook (at least some versions) cannot, and report that the attachment is corrupt.

When sending binary attachments from MarkLogic via xdmp:email
, this wrapping does not occur - causing some recipients to report documents are corrupt.

In order to fix this, we created a function which wraps the base64 encoding prior to sending.

(: Function used for wrapping email attachments :)
declare function local:wrap($wrapped, $unwrapped, $max){
        let $remaining := string-length($unwrapped)

        return if ($remaining <= $max) then concat($wrapped, "&#13;&#10;", substring($unwrapped, 1, $max))
        else local:wrap(concat($wrapped, "&#13;&#10;", substring($unwrapped, 1, $max)), substring($unwrapped, $max+1, $remaining), $max)
};
And it used when building the parameter list:
        let $attachment1 := local:wrap("", xs:string(xs:base64Binary(doc("/some/doc/path/doc.pdf"))), 76)
See documentation on xdmp:email for complete example with attachments.