Poco::TypeList

Modern C++ Design という本にある Loki::Typelist の Poco 版 Poco::TypeList を紹介します。

今回紹介するコードは、前回の Poco::DigestEngine の記事にあるコードを、Poco::TypeList を使ってテンプレートで書き直したもので、処理内容は前回と同一です。

(実は、最初にこちらのソースで書いたのですが、いきなりテンプレートや Poco::TypeList を使うと
 分かりにくいかと思い、2段階攻撃にしました)

ただの書き直しだけではつまらないので、HTTP でファイルを取得する箇所を Poco::HTTPClientSession の記事の時に作った HTTPGetter から、Poco::URIStreamOpener に変更しました。

(2011.02.28 追記)
・dos.close(); を呼ぶのを忘れていたため、正しい結果になっていなかったのを修正しました。
(2011.08.31 追記)
・Poco v1.4.2 で、Poco::MD2Engine が無くなったのに対応しました。

TypeListTest.cpp

・Poco::HTTPClientSession の記事の時に使った http://poco.roundsquare.net/downloads/test.txt にある
 テキストファイルをダイジェストエンジンに食わせるソースとする。
・予め次のコマンドで作成しておいた結果:

$ openssl dgst -md2 test.txt
$ openssl dgst -md4 test.txt
$ openssl dgst -md5 test.txt
$ openssl dgst -sha1 test.txt
$ openssl dgst -hmac Poco test.txt

 のダイジェスト部分だけを、それぞれ
  http://poco.roundsquare.net/downloads/test.md2
  http://poco.roundsquare.net/downloads/test.md4
  http://poco.roundsquare.net/downloads/test.md5
  http://poco.roundsquare.net/downloads/test.sha1
  http://poco.roundsquare.net/downloads/test.hmac
 というファイルにして置いておく。
・ダイジェストエンジンの出力を Poco::DigestEngine::digestToHex で取り出したものと、上記予め
 作成されたファイルとを比較し、OK/NG を表示。
・eDigestTypeHMAC の場合だけ、エンジンのコンストラクタに引数があるので CreateDigestEngine()
 を特殊化。
・CreateTestDigestEngineInstances を eDigestTypeMD2 でインスタンス化することで、再帰的に
 eDigestTypeHMAC 迄の全てがインスタンス化される。
Poco::Net::HTTPStreamFactory::registerFactory() で、HTTPストリームのオープナーを登録。
・Poco::URIStreamOpener::defaultOpener().open(uri) でストリームを開き、get() で内容を入手。

#include <Poco/URI.h>
#include <Poco/TypeList.h>
#include <Poco/DigestEngine.h>
#ifndef POCO_VERSION
#include <Poco/Version.h>
#endif
#if (POCO_VERSION < 0x01040200)
#include <Poco/MD2Engine.h>
#endif
#include <Poco/MD4Engine.h>
#include <Poco/MD5Engine.h>
#include <Poco/SHA1Engine.h>
#include <Poco/HMACEngine.h>
#include <Poco/DigestStream.h>
#include <Poco/Format.h>
#include <Poco/String.h>
#include <Poco/URIStreamOpener.h>
#include <Poco/Net/HTTPStreamFactory.h>
#include <Poco/StreamCopier.h>
 
#include <string>
#include <sstream>
#include <iostream>
#include <memory>
#include <algorithm>
 
#include "ScopedLogMessage.h"
#include "PrepareConsoleLogger.h"
 
enum DigestType {
#if (POCO_VERSION < 0x01040200)
			eDigestTypeMD2 = 0
		,	eDigestTypeMD4
#else
			eDigestTypeMD4 = 0
#endif
		,	eDigestTypeMD5
		,	eDigestTypeSHA1
		,	eDigestTypeHMAC	};
 
const std::string digestName[] = {
#if (POCO_VERSION < 0x01040200)
			"md2"
		,	"md4"
#else
			"md4"
#endif
		,	"md5"
		,	"sha1"
		,	"hmac"	};
 
const int kNumDigestType = sizeof(digestName)/sizeof(digestName[0]);
 
const char* kPassphrase = "Poco";
 
typedef Poco::TypeListType<
#if (POCO_VERSION < 0x01040200)
			Poco::MD2Engine
		,	Poco::MD4Engine
#else
			Poco::MD4Engine
#endif
		,	Poco::MD5Engine
		,	Poco::SHA1Engine
		,	Poco::HMACEngine<Poco::MD5Engine>
			>::HeadType DigestEngineTypeList;
 
class TestDigestEngineBase
{
public:
	TestDigestEngineBase()
	{
	}
};
 
template<DigestType N>
class TestDigestEngine : public TestDigestEngineBase
{
	typedef typename Poco::TypeGetter<N, DigestEngineTypeList>::HeadType	DigestEngineType;
 
public:
	TestDigestEngine(ScopedLogMessage& msg, const Poco::URI& uri, const char* passphrase=kPassphrase) :
		TestDigestEngineBase()
	{
		CreateDigestEngine(passphrase);
		Poco::DigestOutputStream dos(*m_pDigestEngine);
		std::auto_ptr<std::istream> pStr(Poco::URIStreamOpener::defaultOpener().open(uri));
		Poco::StreamCopier::copyStream(*pStr.get(), dos);
		dos.close();
		std::string digestStr(Poco::DigestEngine::digestToHex(m_pDigestEngine->digest()));
 
		Poco::URI digestUri("http://poco.roundsquare.net/downloads/test."+digestName[N]);
		std::auto_ptr<std::istream> pStrDigest(Poco::URIStreamOpener::defaultOpener().open(digestUri));
		std::stringstream ss;
		Poco::StreamCopier::copyStream(*pStrDigest.get(), ss);
		msg.Message(Poco::format("   %s: %s [%s]"
				,	Poco::toUpper((4 == digestName[N].length()) ? digestName[N]:(" "+digestName[N]))
				,	digestStr
				,	std::string((0 == ss.str().compare(digestStr)) ? "OK":"NG"))	);
	}
	~TestDigestEngine()
	{
		delete m_pDigestEngine;
	}
 
private:
	void CreateDigestEngine(const char* /*passphrase*/)
	{
		m_pDigestEngine = new DigestEngineType;
	}
	Poco::DigestEngine*	m_pDigestEngine;
};
 
template<>
void TestDigestEngine<eDigestTypeHMAC>::CreateDigestEngine(const char* passphrase)
{
	m_pDigestEngine = new DigestEngineType(std::string(passphrase));
}
 
template<DigestType N>
void CreateTestDigestEngineInstances(	std::vector<TestDigestEngineBase*>& vec
				,	ScopedLogMessage& msg
				,	const Poco::URI& uri
				,	const char* passphrase=kPassphrase	)
{
	vec[N] = new TestDigestEngine<N>(msg, uri, passphrase);
	CreateTestDigestEngineInstances<static_cast<DigestType>(N+1)>(vec, msg, uri, passphrase);	// recursive call
}
 
template<>
void CreateTestDigestEngineInstances<eDigestTypeHMAC>(
					std::vector<TestDigestEngineBase*>& vec
				,	ScopedLogMessage& msg
				,	const Poco::URI& uri
				,	const char* passphrase	)
{
	vec[eDigestTypeHMAC] = new TestDigestEngine<eDigestTypeHMAC>(msg, uri, passphrase);
}
 
class DeleteTestDigestEngineInstance
{
public:
	void operator () (TestDigestEngineBase* ptr)
	{
		delete ptr;
	}
};
 
int main(int /*argc*/, char** /*argv*/)
{
	PrepareConsoleLogger logger(Poco::Logger::ROOT, Poco::Message::PRIO_INFORMATION);
 
	ScopedLogMessage msg("TypeListTest ", "start", "end");
 
	Poco::URI uri("http://poco.roundsquare.net/downloads/test.txt");
	Poco::Net::HTTPStreamFactory::registerFactory();
	std::auto_ptr<std::istream> pStr(Poco::URIStreamOpener::defaultOpener().open(uri));
	msg.Message("  source text:");
	Poco::StreamCopier::copyStream(*pStr.get(), std::cout);
 
	std::vector<TestDigestEngineBase*> vec(kNumDigestType);
#if (POCO_VERSION < 0x01040200)
	CreateTestDigestEngineInstances<eDigestTypeMD2>(vec, msg, uri);
#else
	CreateTestDigestEngineInstances<eDigestTypeMD4>(vec, msg, uri);
#endif
	std::for_each(vec.begin(), vec.end(), DeleteTestDigestEngineInstance());
 
	return 0;
}

Results of execution

[0] TypeListTest start
[0]   source text:
---  This is a sample text file for HTTPClientSessionTest  ---
[0]     MD4: 61f79367426e3b0f53428c22cf13dd0a [OK]
[0]     MD5: 1d5acafd189d20e30daca7381e1846a0 [OK]
[0]    SHA1: 085ba5956bb1420f47229ae410a7760f01320ea5 [OK]
[0]    HMAC: e72891e5af825ba8bdd7fe3ced51dac9 [OK]
[0] TypeListTest end

Downloads

ここをクリックすると、makefile や VC++ プロジェクトなど一式がダウンロードできます。
(2013.05.31 updated)
・2010年6月2日からのダウンロード数:812

Subversion

・フリーの Subversion ホスティングサービス Assemblaで、ソースコードを管理しています。

Powered by POCO Copyright © 2010 Round Square Inc. All rights reserved.


  1. Poco v1.4.2 | POCO Fanatic - pingback on April 20, 2013 at 7:47 am

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Trackbacks and Pingbacks: