source: trunk/src-cryptopp/algparam.h

Last change on this file was e230cb0, checked in by David Stainton <dstainton415@…>, at 2016-10-12T13:27:29Z

Add cryptopp from tag CRYPTOPP_5_6_5

  • Property mode set to 100644
File size: 20.0 KB
Line 
1// algparam.h - written and placed in the public domain by Wei Dai
2
3//! \file
4//! \headerfile algparam.h
5//! \brief Classes for working with NameValuePairs
6
7
8#ifndef CRYPTOPP_ALGPARAM_H
9#define CRYPTOPP_ALGPARAM_H
10
11#include "config.h"
12#include "cryptlib.h"
13
14// TODO: fix 6011 when the API/ABI can change
15#if (CRYPTOPP_MSC_VERSION >= 1400)
16# pragma warning(push)
17# pragma warning(disable: 6011 28193)
18#endif
19
20#include "smartptr.h"
21#include "secblock.h"
22#include "integer.h"
23#include "misc.h"
24
25NAMESPACE_BEGIN(CryptoPP)
26
27//! \class ConstByteArrayParameter
28//! \brief Used to pass byte array input as part of a NameValuePairs object
29class ConstByteArrayParameter
30{
31public:
32        //! \brief Construct a ConstByteArrayParameter
33        //! \param data a C-String
34        //! \param deepCopy flag indicating whether the data should be copied
35        //! \details The deepCopy option is used when the NameValuePairs object can't
36        //!   keep a copy of the data available
37        ConstByteArrayParameter(const char *data = NULL, bool deepCopy = false)
38                : m_deepCopy(false), m_data(NULL), m_size(0)
39        {
40                Assign((const byte *)data, data ? strlen(data) : 0, deepCopy);
41        }
42
43        //! \brief Construct a ConstByteArrayParameter
44        //! \param data a memory buffer
45        //! \param size the length of the memory buffer
46        //! \param deepCopy flag indicating whether the data should be copied
47        //! \details The deepCopy option is used when the NameValuePairs object can't
48        //!   keep a copy of the data available
49        ConstByteArrayParameter(const byte *data, size_t size, bool deepCopy = false)
50                : m_deepCopy(false), m_data(NULL), m_size(0)
51        {
52                Assign(data, size, deepCopy);
53        }
54
55        //! \brief Construct a ConstByteArrayParameter
56        //! \tparam T a std::basic_string<char> class
57        //! \param string a std::basic_string<char> class
58        //! \param deepCopy flag indicating whether the data should be copied
59        //! \details The deepCopy option is used when the NameValuePairs object can't
60        //!   keep a copy of the data available
61        template <class T> ConstByteArrayParameter(const T &string, bool deepCopy = false)
62                : m_deepCopy(false), m_data(NULL), m_size(0)
63        {
64                CRYPTOPP_COMPILE_ASSERT(sizeof(CPP_TYPENAME T::value_type) == 1);
65                Assign((const byte *)string.data(), string.size(), deepCopy);
66        }
67
68        //! \brief Assign contents from a memory buffer
69        //! \param data a memory buffer
70        //! \param size the length of the memory buffer
71        //! \param deepCopy flag indicating whether the data should be copied
72        //! \details The deepCopy option is used when the NameValuePairs object can't
73        //!   keep a copy of the data available
74        void Assign(const byte *data, size_t size, bool deepCopy)
75        {
76                // This fires, which means: no data with a size, or data with no size.
77                // CRYPTOPP_ASSERT((data && size) || !(data || size));
78                if (deepCopy)
79                        m_block.Assign(data, size);
80                else
81                {
82                        m_data = data;
83                        m_size = size;
84                }
85                m_deepCopy = deepCopy;
86        }
87
88        //! \brief Pointer to the first byte in the memory block
89        const byte *begin() const {return m_deepCopy ? m_block.begin() : m_data;}
90        //! \brief Pointer beyond the last byte in the memory block
91        const byte *end() const {return m_deepCopy ? m_block.end() : m_data + m_size;}
92        //! \brief Length of the memory block
93        size_t size() const {return m_deepCopy ? m_block.size() : m_size;}
94
95private:
96        bool m_deepCopy;
97        const byte *m_data;
98        size_t m_size;
99        SecByteBlock m_block;
100};
101
102//! \class ByteArrayParameter
103//! \brief Used to pass byte array input as part of a NameValuePairs object
104class ByteArrayParameter
105{
106public:
107        //! \brief Construct a ByteArrayParameter
108        //! \param data a memory buffer
109        //! \param size the length of the memory buffer
110        ByteArrayParameter(byte *data = NULL, unsigned int size = 0)
111                : m_data(data), m_size(size) {}
112
113        //! \brief Construct a ByteArrayParameter
114        //! \param block a SecByteBlock
115        ByteArrayParameter(SecByteBlock &block)
116                : m_data(block.begin()), m_size(block.size()) {}
117
118        //! \brief Pointer to the first byte in the memory block
119        byte *begin() const {return m_data;}
120        //! \brief Pointer beyond the last byte in the memory block
121        byte *end() const {return m_data + m_size;}
122        //! \brief Length of the memory block
123        size_t size() const {return m_size;}
124
125private:
126        byte *m_data;
127        size_t m_size;
128};
129
130//! \class CombinedNameValuePairs
131//! \brief Combines two sets of NameValuePairs
132//! \details CombinedNameValuePairs allows you to provide two sets of of NameValuePairs.
133//!   If a name is not found in the first set, then the second set is searched for the
134//!   name and value pair. The second set of NameValuePairs often provides default values.
135class CRYPTOPP_DLL CombinedNameValuePairs : public NameValuePairs
136{
137public:
138        //! \brief Construct a CombinedNameValuePairs
139        //! \param pairs1 reference to the first set of NameValuePairs
140        //! \param pairs2 reference to the second set of NameValuePairs
141        CombinedNameValuePairs(const NameValuePairs &pairs1, const NameValuePairs &pairs2)
142                : m_pairs1(pairs1), m_pairs2(pairs2) {}
143
144        bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
145
146private:
147        const NameValuePairs &m_pairs1, &m_pairs2;
148};
149
150#ifndef CRYPTOPP_DOXYGEN_PROCESSING
151template <class T, class BASE>
152class GetValueHelperClass
153{
154public:
155        GetValueHelperClass(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst)
156                : m_pObject(pObject), m_name(name), m_valueType(&valueType), m_pValue(pValue), m_found(false), m_getValueNames(false)
157        {
158                if (strcmp(m_name, "ValueNames") == 0)
159                {
160                        m_found = m_getValueNames = true;
161                        NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(std::string), *m_valueType);
162                        if (searchFirst)
163                                searchFirst->GetVoidValue(m_name, valueType, pValue);
164                        if (typeid(T) != typeid(BASE))
165                                pObject->BASE::GetVoidValue(m_name, valueType, pValue);
166                        ((*reinterpret_cast<std::string *>(m_pValue) += "ThisPointer:") += typeid(T).name()) += ';';
167                }
168
169                if (!m_found && strncmp(m_name, "ThisPointer:", 12) == 0 && strcmp(m_name+12, typeid(T).name()) == 0)
170                {
171                        NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T *), *m_valueType);
172                        *reinterpret_cast<const T **>(pValue) = pObject;
173                        m_found = true;
174                        return;
175                }
176
177                if (!m_found && searchFirst)
178                        m_found = searchFirst->GetVoidValue(m_name, valueType, pValue);
179
180                if (!m_found && typeid(T) != typeid(BASE))
181                        m_found = pObject->BASE::GetVoidValue(m_name, valueType, pValue);
182        }
183
184        operator bool() const {return m_found;}
185
186        template <class R>
187        GetValueHelperClass<T,BASE> & operator()(const char *name, const R & (T::*pm)() const)
188        {
189                if (m_getValueNames)
190                        (*reinterpret_cast<std::string *>(m_pValue) += name) += ";";
191                if (!m_found && strcmp(name, m_name) == 0)
192                {
193                        NameValuePairs::ThrowIfTypeMismatch(name, typeid(R), *m_valueType);
194                        *reinterpret_cast<R *>(m_pValue) = (m_pObject->*pm)();
195                        m_found = true;
196                }
197                return *this;
198        }
199
200        GetValueHelperClass<T,BASE> &Assignable()
201        {
202#ifndef __INTEL_COMPILER        // ICL 9.1 workaround: Intel compiler copies the vTable pointer for some reason
203                if (m_getValueNames)
204                        ((*reinterpret_cast<std::string *>(m_pValue) += "ThisObject:") += typeid(T).name()) += ';';
205                if (!m_found && strncmp(m_name, "ThisObject:", 11) == 0 && strcmp(m_name+11, typeid(T).name()) == 0)
206                {
207                        NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T), *m_valueType);
208                        *reinterpret_cast<T *>(m_pValue) = *m_pObject;
209                        m_found = true;
210                }
211#endif
212                return *this;
213        }
214
215private:
216        const T *m_pObject;
217        const char *m_name;
218        const std::type_info *m_valueType;
219        void *m_pValue;
220        bool m_found, m_getValueNames;
221};
222
223template <class BASE, class T>
224GetValueHelperClass<T, BASE> GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULL, BASE *dummy=NULL)
225{
226        CRYPTOPP_UNUSED(dummy);
227        return GetValueHelperClass<T, BASE>(pObject, name, valueType, pValue, searchFirst);
228}
229
230template <class T>
231GetValueHelperClass<T, T> GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULL)
232{
233        return GetValueHelperClass<T, T>(pObject, name, valueType, pValue, searchFirst);
234}
235
236// ********************************************************
237
238// VC60 workaround
239#if defined(_MSC_VER) && (_MSC_VER < 1300)
240template <class R>
241R Hack_DefaultValueFromConstReferenceType(const R &)
242{
243        return R();
244}
245
246template <class R>
247bool Hack_GetValueIntoConstReference(const NameValuePairs &source, const char *name, const R &value)
248{
249        return source.GetValue(name, const_cast<R &>(value));
250}
251
252template <class T, class BASE>
253class AssignFromHelperClass
254{
255public:
256        AssignFromHelperClass(T *pObject, const NameValuePairs &source)
257                : m_pObject(pObject), m_source(source), m_done(false)
258        {
259                if (source.GetThisObject(*pObject))
260                        m_done = true;
261                else if (typeid(BASE) != typeid(T))
262                        pObject->BASE::AssignFrom(source);
263        }
264
265        template <class R>
266        AssignFromHelperClass & operator()(const char *name, void (T::*pm)(R))  // VC60 workaround: "const R &" here causes compiler error
267        {
268                if (!m_done)
269                {
270                        R value = Hack_DefaultValueFromConstReferenceType(reinterpret_cast<R>(*(int *)NULL));
271                        if (!Hack_GetValueIntoConstReference(m_source, name, value))
272                                throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name + "'");
273                        (m_pObject->*pm)(value);
274                }
275                return *this;
276        }
277
278        template <class R, class S>
279        AssignFromHelperClass & operator()(const char *name1, const char *name2, void (T::*pm)(R, S))   // VC60 workaround: "const R &" here causes compiler error
280        {
281                if (!m_done)
282                {
283                        R value1 = Hack_DefaultValueFromConstReferenceType(reinterpret_cast<R>(*(int *)NULL));
284                        if (!Hack_GetValueIntoConstReference(m_source, name1, value1))
285                                throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name1 + "'");
286                        S value2 = Hack_DefaultValueFromConstReferenceType(reinterpret_cast<S>(*(int *)NULL));
287                        if (!Hack_GetValueIntoConstReference(m_source, name2, value2))
288                                throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name2 + "'");
289                        (m_pObject->*pm)(value1, value2);
290                }
291                return *this;
292        }
293
294private:
295        T *m_pObject;
296        const NameValuePairs &m_source;
297        bool m_done;
298};
299#else
300template <class T, class BASE>
301class AssignFromHelperClass
302{
303public:
304        AssignFromHelperClass(T *pObject, const NameValuePairs &source)
305                : m_pObject(pObject), m_source(source), m_done(false)
306        {
307                if (source.GetThisObject(*pObject))
308                        m_done = true;
309                else if (typeid(BASE) != typeid(T))
310                        pObject->BASE::AssignFrom(source);
311        }
312
313        template <class R>
314        AssignFromHelperClass & operator()(const char *name, void (T::*pm)(const R&))
315        {
316                if (!m_done)
317                {
318                        R value;
319                        if (!m_source.GetValue(name, value))
320                                throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name + "'");
321                        (m_pObject->*pm)(value);
322                }
323                return *this;
324        }
325
326        template <class R, class S>
327        AssignFromHelperClass & operator()(const char *name1, const char *name2, void (T::*pm)(const R&, const S&))
328        {
329                if (!m_done)
330                {
331                        R value1;
332                        if (!m_source.GetValue(name1, value1))
333                                throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name1 + "'");
334                        S value2;
335                        if (!m_source.GetValue(name2, value2))
336                                throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name2 + "'");
337                        (m_pObject->*pm)(value1, value2);
338                }
339                return *this;
340        }
341
342private:
343        T *m_pObject;
344        const NameValuePairs &m_source;
345        bool m_done;
346};
347#endif
348
349template <class BASE, class T>
350AssignFromHelperClass<T, BASE> AssignFromHelper(T *pObject, const NameValuePairs &source, BASE *dummy=NULL)
351{
352        CRYPTOPP_UNUSED(dummy);
353        return AssignFromHelperClass<T, BASE>(pObject, source);
354}
355
356template <class T>
357AssignFromHelperClass<T, T> AssignFromHelper(T *pObject, const NameValuePairs &source)
358{
359        return AssignFromHelperClass<T, T>(pObject, source);
360}
361
362#endif // CRYPTOPP_DOXYGEN_PROCESSING
363
364// ********************************************************
365
366// to allow the linker to discard Integer code if not needed.
367typedef bool (CRYPTOPP_API * PAssignIntToInteger)(const std::type_info &valueType, void *pInteger, const void *pInt);
368CRYPTOPP_DLL extern PAssignIntToInteger g_pAssignIntToInteger;
369
370CRYPTOPP_DLL const std::type_info & CRYPTOPP_API IntegerTypeId();
371
372//! \class AlgorithmParametersBase
373//! \brief Base class for AlgorithmParameters
374class CRYPTOPP_DLL AlgorithmParametersBase
375{
376public:
377        //! \class ParameterNotUsed
378        //! \brief Exception thrown when an AlgorithmParameter is unused
379        class ParameterNotUsed : public Exception
380        {
381        public:
382                ParameterNotUsed(const char *name) : Exception(OTHER_ERROR, std::string("AlgorithmParametersBase: parameter \"") + name + "\" not used") {}
383        };
384
385        // this is actually a move, not a copy
386        AlgorithmParametersBase(const AlgorithmParametersBase &x)
387                : m_name(x.m_name), m_throwIfNotUsed(x.m_throwIfNotUsed), m_used(x.m_used)
388        {
389                m_next.reset(const_cast<AlgorithmParametersBase &>(x).m_next.release());
390                x.m_used = true;
391        }
392
393        //! \brief Construct a AlgorithmParametersBase
394        //! \param name the parameter name
395        //! \param throwIfNotUsed flags indicating whether an exception should be thrown
396        //! \details If throwIfNotUsed is true, then a ParameterNotUsed exception
397        //!   will be thrown in the destructor if the parameter is not not retrieved.
398        AlgorithmParametersBase(const char *name, bool throwIfNotUsed)
399                : m_name(name), m_throwIfNotUsed(throwIfNotUsed), m_used(false) {}
400
401        virtual ~AlgorithmParametersBase() CRYPTOPP_THROW
402        {
403#ifdef CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE
404                if (!std::uncaught_exception())
405#else
406                try
407#endif
408                {
409                        if (m_throwIfNotUsed && !m_used)
410                                throw ParameterNotUsed(m_name);
411                }
412#ifndef CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE
413                catch(const Exception&)
414                {
415                }
416#endif
417        }
418
419        bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
420
421protected:
422        friend class AlgorithmParameters;
423        void operator=(const AlgorithmParametersBase& rhs);     // assignment not allowed, declare this for VC60
424
425        virtual void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const =0;
426        virtual void MoveInto(void *p) const =0;        // not really const
427
428        const char *m_name;
429        bool m_throwIfNotUsed;
430        mutable bool m_used;
431        member_ptr<AlgorithmParametersBase> m_next;
432};
433
434//! \class AlgorithmParametersTemplate
435//! \brief Template base class for AlgorithmParameters
436//! \tparam T the class or type
437template <class T>
438class AlgorithmParametersTemplate : public AlgorithmParametersBase
439{
440public:
441        //! \brief Construct an AlgorithmParametersTemplate
442        //! \param name the name of the value
443        //! \param value a reference to the value
444        //! \param throwIfNotUsed flags indicating whether an exception should be thrown
445        //! \details If throwIfNotUsed is true, then a ParameterNotUsed exception
446        //!   will be thrown in the destructor if the parameter is not not retrieved.
447        AlgorithmParametersTemplate(const char *name, const T &value, bool throwIfNotUsed)
448                : AlgorithmParametersBase(name, throwIfNotUsed), m_value(value)
449        {
450        }
451
452        void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const
453        {
454                // special case for retrieving an Integer parameter when an int was passed in
455                if (!(g_pAssignIntToInteger != NULL && typeid(T) == typeid(int) && g_pAssignIntToInteger(valueType, pValue, &m_value)))
456                {
457                        NameValuePairs::ThrowIfTypeMismatch(name, typeid(T), valueType);
458                        *reinterpret_cast<T *>(pValue) = m_value;
459                }
460        }
461
462#if defined(DEBUG_NEW) && (_MSC_VER >= 1300)
463# pragma push_macro("new")
464# undef new
465#endif
466
467        void MoveInto(void *buffer) const
468        {
469                AlgorithmParametersTemplate<T>* p = new(buffer) AlgorithmParametersTemplate<T>(*this);
470                CRYPTOPP_UNUSED(p);     // silence warning
471        }
472
473#if defined(DEBUG_NEW) && (_MSC_VER >= 1300)
474# pragma pop_macro("new")
475#endif
476
477protected:
478        T m_value;
479};
480
481CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate<bool>;
482CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate<int>;
483CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate<ConstByteArrayParameter>;
484
485//! \class AlgorithmParameters
486//! \brief An object that implements NameValuePairs
487//! \tparam T the class or type
488//! \param name the name of the object or value to retrieve
489//! \param value reference to a variable that receives the value
490//! \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed
491//! \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(),
492//!   such as MSVC 7.0 and earlier.
493//! \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by
494//!   repeatedly using operator() on the object returned by MakeParameters, for example:
495//!   <pre>
496//!     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
497//!   </pre>
498class CRYPTOPP_DLL AlgorithmParameters : public NameValuePairs
499{
500public:
501        AlgorithmParameters();
502
503#ifdef __BORLANDC__
504        template <class T>
505        AlgorithmParameters(const char *name, const T &value, bool throwIfNotUsed=true)
506                : m_next(new AlgorithmParametersTemplate<T>(name, value, throwIfNotUsed))
507                , m_defaultThrowIfNotUsed(throwIfNotUsed)
508        {
509        }
510#endif
511
512        AlgorithmParameters(const AlgorithmParameters &x);
513
514        AlgorithmParameters & operator=(const AlgorithmParameters &x);
515
516        //! \tparam T the class or type
517        //! \param name the name of the object or value to retrieve
518        //! \param value reference to a variable that receives the value
519        //! \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed
520        template <class T>
521        AlgorithmParameters & operator()(const char *name, const T &value, bool throwIfNotUsed)
522        {
523                member_ptr<AlgorithmParametersBase> p(new AlgorithmParametersTemplate<T>(name, value, throwIfNotUsed));
524                p->m_next.reset(m_next.release());
525                m_next.reset(p.release());
526                m_defaultThrowIfNotUsed = throwIfNotUsed;
527                return *this;
528        }
529
530        //! \brief Appends a NameValuePair to a collection of NameValuePairs
531        //! \tparam T the class or type
532        //! \param name the name of the object or value to retrieve
533        //! \param value reference to a variable that receives the value
534        template <class T>
535        AlgorithmParameters & operator()(const char *name, const T &value)
536        {
537                return operator()(name, value, m_defaultThrowIfNotUsed);
538        }
539
540        bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
541
542protected:
543        member_ptr<AlgorithmParametersBase> m_next;
544        bool m_defaultThrowIfNotUsed;
545};
546
547//! \brief Create an object that implements NameValuePairs
548//! \tparam T the class or type
549//! \param name the name of the object or value to retrieve
550//! \param value reference to a variable that receives the value
551//! \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed
552//! \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(),
553//!   such as MSVC 7.0 and earlier.
554//! \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by
555//!   repeatedly using \p operator() on the object returned by \p MakeParameters, for example:
556//!   <pre>
557//!     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
558//!   </pre>
559#ifdef __BORLANDC__
560typedef AlgorithmParameters MakeParameters;
561#else
562template <class T>
563AlgorithmParameters MakeParameters(const char *name, const T &value, bool throwIfNotUsed = true)
564{
565        return AlgorithmParameters()(name, value, throwIfNotUsed);
566}
567#endif
568
569#define CRYPTOPP_GET_FUNCTION_ENTRY(name)               (Name::name(), &ThisClass::Get##name)
570#define CRYPTOPP_SET_FUNCTION_ENTRY(name)               (Name::name(), &ThisClass::Set##name)
571#define CRYPTOPP_SET_FUNCTION_ENTRY2(name1, name2)      (Name::name1(), Name::name2(), &ThisClass::Set##name1##And##name2)
572
573// TODO: fix 6011 when the API/ABI can change
574#if (CRYPTOPP_MSC_VERSION >= 1400)
575# pragma warning(pop)
576#endif
577
578NAMESPACE_END
579
580#endif
Note: See TracBrowser for help on using the repository browser.