--- /dev/null
+#include <list>
+#include <string>
+#include <msp/core/application.h>
+#include <msp/core/getopt.h>
+#include <msp/crypto/md5.h>
+#include <msp/crypto/sha2.h>
+#include <msp/io/file.h>
+#include <msp/io/print.h>
+
+using namespace std;
+using namespace Msp;
+
+class Checksum: public Msp::RegisteredApplication<Checksum>
+{
+private:
+ bool do_md5;
+ bool do_sha256;
+ bool do_sha512;
+ list<string> files;
+
+public:
+ Checksum(int, char **);
+
+ virtual int main();
+private:
+ template<typename H>
+ void process_file(const std::string &);
+};
+
+Checksum::Checksum(int argc, char **argv):
+ do_md5(false),
+ do_sha256(false),
+ do_sha512(false)
+{
+
+ GetOpt getopt;
+ getopt.add_option("md5", do_md5, GetOpt::NO_ARG);
+ getopt.add_option("sha256", do_sha256, GetOpt::NO_ARG);
+ getopt.add_option("sha512", do_sha512, GetOpt::NO_ARG);
+ getopt.add_argument("file", files, GetOpt::REQUIRED_ARG);
+ getopt(argc, argv);
+
+ if(!do_md5 && !do_sha256 && !do_sha512)
+ do_md5 = true;
+}
+
+int Checksum::main()
+{
+ for(list<string>::const_iterator i=files.begin(); i!=files.end(); ++i)
+ {
+ if(do_md5)
+ process_file<Crypto::MD5>(*i);
+ if(do_sha256)
+ process_file<Crypto::SHA256>(*i);
+ if(do_sha512)
+ process_file<Crypto::SHA512>(*i);
+ }
+ return 0;
+}
+
+template<typename H>
+void Checksum::process_file(const string &fn)
+{
+ IO::BufferedFile infile(fn);
+ H hash;
+ while(1)
+ {
+ char buffer[16384];
+ unsigned len = infile.read(buffer, sizeof(buffer));
+ if(!len)
+ break;
+ hash.update(buffer, len);
+ }
+ IO::print("%s %s\n", hash.get_hexdigest(), fn);
+}