Checksums with FreshMarker File

Some time ago, I had the idea that a checksum calculation could be added to the FreshMarker File library. FreshMarker File is an extension for FreshMarker to support the Java types File and Path. A checksum support would allow the current checksum to be added to lists of files without any major detours. The idea is quite simple. A corresponding built-in is appended behind a file or path variable.

name:    ${path?name}
MD5:     ${path?md5}
SHA-256: ${path?sha256}

The template shown here displays the name of a file and its MD5 or SHA-256 checksums.

Checksums can be easily calculated in Java using the existing on-board tools.

private static TemplateString checksum(String algorithm, Path value) {
  try (SeekableByteChannel ch = Files.newByteChannel(value, StandardOpenOption.READ)) {
    MessageDigest md = MessageDigest.getInstance(algorithm);
    ByteBuffer bf = ByteBuffer.allocate(1000);
    while (ch.read(bf) > 0) {
      bf.flip();
      md.update(bf);
      bf.clear();
    }
    byte[] digest = md.digest();
    return new TemplateString(new BigInteger(1, digest).toString(16));
  } catch (NoSuchAlgorithmException | IOException ex) {
    throw new ProcessException("cannot calculate digest", ex);
  }
}

The method shown here uses the MessageDigest class to calculate a checksum from the contents of a file. MessageDigest typically offers MD5, SHA1, SHA-256, SHA-384, and SHA-512 as algorithms, so we provide plugins for all five.

register.add(TemplatePath.class, "md5", (x, y, e) -> checksum((TemplatePath)x, e, "MD5"));
register.add(TemplatePath.class, "sha", (x, y, e) -> checksum((TemplatePath)x, e, "SHA-1"));
register.add(TemplatePath.class, "sha1", (x, y, e) -> checksum((TemplatePath)x, e, "SHA-1"));
register.add(TemplatePath.class, "sha256", (x, y, e) -> checksum((TemplatePath)x, e, "SHA-256"));
register.add(TemplatePath.class, "sha384", (x, y, e) -> checksum((TemplatePath)x, e, "SHA-384"));
register.add(TemplatePath.class, "sha512", (x, y, e) -> checksum((TemplatePath)x, e, "SHA-512"));
register.add(TemplateFile.class, "md5", (x, y, e) -> checksum((TemplateFile)x, e, "MD5"));
register.add(TemplateFile.class, "sha", (x, y, e) -> checksum((TemplateFile)x, e, "SHA-1"));
register.add(TemplateFile.class, "sha1", (x, y, e) -> checksum((TemplateFile)x, e, "SHA-1"));
register.add(TemplateFile.class, "sha256", (x, y, e) -> checksum((TemplateFile)x, e, "SHA-256"));
register.add(TemplateFile.class, "sha384", (x, y, e) -> checksum((TemplateFile)x, e, "SHA-384"));
register.add(TemplateFile.class, "sha512", (x, y, e) -> checksum((TemplateFile)x, e, "SHA-512"));

This completes the implementation. For an image file named pandemoinum.png with the content shown on the left, the output on the right is generated.

name:    pandemonium.png
MD5:     e41549a50dc7f2abb5463176c77ee71a
SHA-256: f091aaa9a206aff762181bde2f1197e20b1e9039815eb9f0b53aced1c28ff165

The built-ins are included in the latest version of FreshMarker File 2.5.3. Enjoy!

Leave a Comment