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日からのダウンロード数:1080
Subversion
・フリーの Subversion ホスティングサービス Assemblaで、ソースコードを管理しています。
![]() |
Copyright © 2010 Round Square Inc. All rights reserved. |
---|
1 Comments.