Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

509 lines
16 KiB

  1. // algparam.h - written and placed in the public domain by Wei Dai
  2. //! \file
  3. //! \headerfile algparam.h
  4. //! \brief Classes for working with NameValuePairs
  5. #ifndef CRYPTOPP_ALGPARAM_H
  6. #define CRYPTOPP_ALGPARAM_H
  7. #include "cryptlib.h"
  8. #include "config.h"
  9. // TODO: fix 6011 when the API/ABI can change
  10. #if (CRYPTOPP_MSC_VERSION >= 1400)
  11. # pragma warning(push)
  12. # pragma warning(disable: 6011 28193)
  13. #endif
  14. #include "smartptr.h"
  15. #include "secblock.h"
  16. #include "integer.h"
  17. #include "misc.h"
  18. NAMESPACE_BEGIN(CryptoPP)
  19. //! used to pass byte array input as part of a NameValuePairs object
  20. /*! the deepCopy option is used when the NameValuePairs object can't
  21. keep a copy of the data available */
  22. class ConstByteArrayParameter
  23. {
  24. public:
  25. ConstByteArrayParameter(const char *data = NULL, bool deepCopy = false)
  26. : m_deepCopy(false), m_data(NULL), m_size(0)
  27. {
  28. Assign((const byte *)data, data ? strlen(data) : 0, deepCopy);
  29. }
  30. ConstByteArrayParameter(const byte *data, size_t size, bool deepCopy = false)
  31. : m_deepCopy(false), m_data(NULL), m_size(0)
  32. {
  33. Assign(data, size, deepCopy);
  34. }
  35. template <class T> ConstByteArrayParameter(const T &string, bool deepCopy = false)
  36. : m_deepCopy(false), m_data(NULL), m_size(0)
  37. {
  38. CRYPTOPP_COMPILE_ASSERT(sizeof(CPP_TYPENAME T::value_type) == 1);
  39. Assign((const byte *)string.data(), string.size(), deepCopy);
  40. }
  41. void Assign(const byte *data, size_t size, bool deepCopy)
  42. {
  43. // This fires, which means: no data with a size, or data with no size.
  44. // assert((data && size) || !(data || size));
  45. if (deepCopy)
  46. m_block.Assign(data, size);
  47. else
  48. {
  49. m_data = data;
  50. m_size = size;
  51. }
  52. m_deepCopy = deepCopy;
  53. }
  54. const byte *begin() const {return m_deepCopy ? m_block.begin() : m_data;}
  55. const byte *end() const {return m_deepCopy ? m_block.end() : m_data + m_size;}
  56. size_t size() const {return m_deepCopy ? m_block.size() : m_size;}
  57. private:
  58. bool m_deepCopy;
  59. const byte *m_data;
  60. size_t m_size;
  61. SecByteBlock m_block;
  62. };
  63. class ByteArrayParameter
  64. {
  65. public:
  66. ByteArrayParameter(byte *data = NULL, unsigned int size = 0)
  67. : m_data(data), m_size(size) {}
  68. ByteArrayParameter(SecByteBlock &block)
  69. : m_data(block.begin()), m_size(block.size()) {}
  70. byte *begin() const {return m_data;}
  71. byte *end() const {return m_data + m_size;}
  72. size_t size() const {return m_size;}
  73. private:
  74. byte *m_data;
  75. size_t m_size;
  76. };
  77. class CRYPTOPP_DLL CombinedNameValuePairs : public NameValuePairs
  78. {
  79. public:
  80. CombinedNameValuePairs(const NameValuePairs &pairs1, const NameValuePairs &pairs2)
  81. : m_pairs1(pairs1), m_pairs2(pairs2) {}
  82. bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
  83. private:
  84. const NameValuePairs &m_pairs1, &m_pairs2;
  85. };
  86. template <class T, class BASE>
  87. class GetValueHelperClass
  88. {
  89. public:
  90. GetValueHelperClass(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst)
  91. : m_pObject(pObject), m_name(name), m_valueType(&valueType), m_pValue(pValue), m_found(false), m_getValueNames(false)
  92. {
  93. if (strcmp(m_name, "ValueNames") == 0)
  94. {
  95. m_found = m_getValueNames = true;
  96. NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(std::string), *m_valueType);
  97. if (searchFirst)
  98. searchFirst->GetVoidValue(m_name, valueType, pValue);
  99. if (typeid(T) != typeid(BASE))
  100. pObject->BASE::GetVoidValue(m_name, valueType, pValue);
  101. ((*reinterpret_cast<std::string *>(m_pValue) += "ThisPointer:") += typeid(T).name()) += ';';
  102. }
  103. if (!m_found && strncmp(m_name, "ThisPointer:", 12) == 0 && strcmp(m_name+12, typeid(T).name()) == 0)
  104. {
  105. NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T *), *m_valueType);
  106. *reinterpret_cast<const T **>(pValue) = pObject;
  107. m_found = true;
  108. return;
  109. }
  110. if (!m_found && searchFirst)
  111. m_found = searchFirst->GetVoidValue(m_name, valueType, pValue);
  112. if (!m_found && typeid(T) != typeid(BASE))
  113. m_found = pObject->BASE::GetVoidValue(m_name, valueType, pValue);
  114. }
  115. operator bool() const {return m_found;}
  116. template <class R>
  117. GetValueHelperClass<T,BASE> & operator()(const char *name, const R & (T::*pm)() const)
  118. {
  119. if (m_getValueNames)
  120. (*reinterpret_cast<std::string *>(m_pValue) += name) += ";";
  121. if (!m_found && strcmp(name, m_name) == 0)
  122. {
  123. NameValuePairs::ThrowIfTypeMismatch(name, typeid(R), *m_valueType);
  124. *reinterpret_cast<R *>(m_pValue) = (m_pObject->*pm)();
  125. m_found = true;
  126. }
  127. return *this;
  128. }
  129. GetValueHelperClass<T,BASE> &Assignable()
  130. {
  131. #ifndef __INTEL_COMPILER // ICL 9.1 workaround: Intel compiler copies the vTable pointer for some reason
  132. if (m_getValueNames)
  133. ((*reinterpret_cast<std::string *>(m_pValue) += "ThisObject:") += typeid(T).name()) += ';';
  134. if (!m_found && strncmp(m_name, "ThisObject:", 11) == 0 && strcmp(m_name+11, typeid(T).name()) == 0)
  135. {
  136. NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T), *m_valueType);
  137. *reinterpret_cast<T *>(m_pValue) = *m_pObject;
  138. m_found = true;
  139. }
  140. #endif
  141. return *this;
  142. }
  143. private:
  144. const T *m_pObject;
  145. const char *m_name;
  146. const std::type_info *m_valueType;
  147. void *m_pValue;
  148. bool m_found, m_getValueNames;
  149. };
  150. template <class BASE, class T>
  151. GetValueHelperClass<T, BASE> GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULL, BASE *dummy=NULL)
  152. {
  153. CRYPTOPP_UNUSED(dummy);
  154. return GetValueHelperClass<T, BASE>(pObject, name, valueType, pValue, searchFirst);
  155. }
  156. template <class T>
  157. GetValueHelperClass<T, T> GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULL)
  158. {
  159. return GetValueHelperClass<T, T>(pObject, name, valueType, pValue, searchFirst);
  160. }
  161. // ********************************************************
  162. // VC60 workaround
  163. #if defined(_MSC_VER) && (_MSC_VER < 1300)
  164. template <class R>
  165. R Hack_DefaultValueFromConstReferenceType(const R &)
  166. {
  167. return R();
  168. }
  169. template <class R>
  170. bool Hack_GetValueIntoConstReference(const NameValuePairs &source, const char *name, const R &value)
  171. {
  172. return source.GetValue(name, const_cast<R &>(value));
  173. }
  174. template <class T, class BASE>
  175. class AssignFromHelperClass
  176. {
  177. public:
  178. AssignFromHelperClass(T *pObject, const NameValuePairs &source)
  179. : m_pObject(pObject), m_source(source), m_done(false)
  180. {
  181. if (source.GetThisObject(*pObject))
  182. m_done = true;
  183. else if (typeid(BASE) != typeid(T))
  184. pObject->BASE::AssignFrom(source);
  185. }
  186. template <class R>
  187. AssignFromHelperClass & operator()(const char *name, void (T::*pm)(R)) // VC60 workaround: "const R &" here causes compiler error
  188. {
  189. if (!m_done)
  190. {
  191. R value = Hack_DefaultValueFromConstReferenceType(reinterpret_cast<R>(*(int *)NULL));
  192. if (!Hack_GetValueIntoConstReference(m_source, name, value))
  193. throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name + "'");
  194. (m_pObject->*pm)(value);
  195. }
  196. return *this;
  197. }
  198. template <class R, class S>
  199. AssignFromHelperClass & operator()(const char *name1, const char *name2, void (T::*pm)(R, S)) // VC60 workaround: "const R &" here causes compiler error
  200. {
  201. if (!m_done)
  202. {
  203. R value1 = Hack_DefaultValueFromConstReferenceType(reinterpret_cast<R>(*(int *)NULL));
  204. if (!Hack_GetValueIntoConstReference(m_source, name1, value1))
  205. throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name1 + "'");
  206. S value2 = Hack_DefaultValueFromConstReferenceType(reinterpret_cast<S>(*(int *)NULL));
  207. if (!Hack_GetValueIntoConstReference(m_source, name2, value2))
  208. throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name2 + "'");
  209. (m_pObject->*pm)(value1, value2);
  210. }
  211. return *this;
  212. }
  213. private:
  214. T *m_pObject;
  215. const NameValuePairs &m_source;
  216. bool m_done;
  217. };
  218. #else
  219. template <class T, class BASE>
  220. class AssignFromHelperClass
  221. {
  222. public:
  223. AssignFromHelperClass(T *pObject, const NameValuePairs &source)
  224. : m_pObject(pObject), m_source(source), m_done(false)
  225. {
  226. if (source.GetThisObject(*pObject))
  227. m_done = true;
  228. else if (typeid(BASE) != typeid(T))
  229. pObject->BASE::AssignFrom(source);
  230. }
  231. template <class R>
  232. AssignFromHelperClass & operator()(const char *name, void (T::*pm)(const R&))
  233. {
  234. if (!m_done)
  235. {
  236. R value;
  237. if (!m_source.GetValue(name, value))
  238. throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name + "'");
  239. (m_pObject->*pm)(value);
  240. }
  241. return *this;
  242. }
  243. template <class R, class S>
  244. AssignFromHelperClass & operator()(const char *name1, const char *name2, void (T::*pm)(const R&, const S&))
  245. {
  246. if (!m_done)
  247. {
  248. R value1;
  249. if (!m_source.GetValue(name1, value1))
  250. throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name1 + "'");
  251. S value2;
  252. if (!m_source.GetValue(name2, value2))
  253. throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name2 + "'");
  254. (m_pObject->*pm)(value1, value2);
  255. }
  256. return *this;
  257. }
  258. private:
  259. T *m_pObject;
  260. const NameValuePairs &m_source;
  261. bool m_done;
  262. };
  263. #endif
  264. template <class BASE, class T>
  265. AssignFromHelperClass<T, BASE> AssignFromHelper(T *pObject, const NameValuePairs &source, BASE *dummy=NULL)
  266. {
  267. CRYPTOPP_UNUSED(dummy);
  268. return AssignFromHelperClass<T, BASE>(pObject, source);
  269. }
  270. template <class T>
  271. AssignFromHelperClass<T, T> AssignFromHelper(T *pObject, const NameValuePairs &source)
  272. {
  273. return AssignFromHelperClass<T, T>(pObject, source);
  274. }
  275. // ********************************************************
  276. // to allow the linker to discard Integer code if not needed.
  277. typedef bool (CRYPTOPP_API * PAssignIntToInteger)(const std::type_info &valueType, void *pInteger, const void *pInt);
  278. CRYPTOPP_DLL extern PAssignIntToInteger g_pAssignIntToInteger;
  279. CRYPTOPP_DLL const std::type_info & CRYPTOPP_API IntegerTypeId();
  280. class CRYPTOPP_DLL AlgorithmParametersBase
  281. {
  282. public:
  283. class ParameterNotUsed : public Exception
  284. {
  285. public:
  286. ParameterNotUsed(const char *name) : Exception(OTHER_ERROR, std::string("AlgorithmParametersBase: parameter \"") + name + "\" not used") {}
  287. };
  288. // this is actually a move, not a copy
  289. AlgorithmParametersBase(const AlgorithmParametersBase &x)
  290. : m_name(x.m_name), m_throwIfNotUsed(x.m_throwIfNotUsed), m_used(x.m_used)
  291. {
  292. m_next.reset(const_cast<AlgorithmParametersBase &>(x).m_next.release());
  293. x.m_used = true;
  294. }
  295. AlgorithmParametersBase(const char *name, bool throwIfNotUsed)
  296. : m_name(name), m_throwIfNotUsed(throwIfNotUsed), m_used(false) {}
  297. virtual ~AlgorithmParametersBase() CRYPTOPP_THROW
  298. {
  299. #ifdef CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE
  300. if (!std::uncaught_exception())
  301. #else
  302. try
  303. #endif
  304. {
  305. if (m_throwIfNotUsed && !m_used)
  306. throw ParameterNotUsed(m_name);
  307. }
  308. #ifndef CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE
  309. catch(const Exception&)
  310. {
  311. }
  312. #endif
  313. }
  314. bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
  315. protected:
  316. friend class AlgorithmParameters;
  317. void operator=(const AlgorithmParametersBase& rhs); // assignment not allowed, declare this for VC60
  318. virtual void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const =0;
  319. //VALVE: Our debug allocator doesn't implement placement new, and this function is never
  320. // actually called.
  321. //virtual void MoveInto(void *p) const =0; // not really const
  322. const char *m_name;
  323. bool m_throwIfNotUsed;
  324. mutable bool m_used;
  325. member_ptr<AlgorithmParametersBase> m_next;
  326. };
  327. template <class T>
  328. class AlgorithmParametersTemplate : public AlgorithmParametersBase
  329. {
  330. public:
  331. AlgorithmParametersTemplate(const char *name, const T &value, bool throwIfNotUsed)
  332. : AlgorithmParametersBase(name, throwIfNotUsed), m_value(value)
  333. {
  334. }
  335. void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const
  336. {
  337. // special case for retrieving an Integer parameter when an int was passed in
  338. if (!(g_pAssignIntToInteger != NULL && typeid(T) == typeid(int) && g_pAssignIntToInteger(valueType, pValue, &m_value)))
  339. {
  340. NameValuePairs::ThrowIfTypeMismatch(name, typeid(T), valueType);
  341. *reinterpret_cast<T *>(pValue) = m_value;
  342. }
  343. }
  344. //VALVE: Our debug allocator doesn't implement placement new, and this function is never
  345. // actually called.
  346. //void MoveInto(void *buffer) const
  347. //{
  348. // AlgorithmParametersTemplate<T>* p = new(buffer) AlgorithmParametersTemplate<T>(*this);
  349. // CRYPTOPP_UNUSED(p); // silence warning
  350. //}
  351. protected:
  352. T m_value;
  353. };
  354. CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate<bool>;
  355. CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate<int>;
  356. CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate<ConstByteArrayParameter>;
  357. //! \class AlgorithmParameters
  358. //! \brief An object that implements NameValuePairs
  359. //! \tparam T the class or type
  360. //! \param name the name of the object or value to retrieve
  361. //! \param value reference to a variable that receives the value
  362. //! \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed
  363. //! \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(),
  364. //! such as MSVC 7.0 and earlier.
  365. //! \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by
  366. //! repeatedly using operator() on the object returned by MakeParameters, for example:
  367. //! <pre>
  368. //! AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
  369. //! </pre>
  370. class CRYPTOPP_DLL AlgorithmParameters : public NameValuePairs
  371. {
  372. public:
  373. AlgorithmParameters();
  374. #ifdef __BORLANDC__
  375. template <class T>
  376. AlgorithmParameters(const char *name, const T &value, bool throwIfNotUsed=true)
  377. : m_next(new AlgorithmParametersTemplate<T>(name, value, throwIfNotUsed))
  378. , m_defaultThrowIfNotUsed(throwIfNotUsed)
  379. {
  380. }
  381. #endif
  382. AlgorithmParameters(const AlgorithmParameters &x);
  383. AlgorithmParameters & operator=(const AlgorithmParameters &x);
  384. //! \tparam T the class or type
  385. //! \param name the name of the object or value to retrieve
  386. //! \param value reference to a variable that receives the value
  387. //! \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed
  388. template <class T>
  389. AlgorithmParameters & operator()(const char *name, const T &value, bool throwIfNotUsed)
  390. {
  391. member_ptr<AlgorithmParametersBase> p(new AlgorithmParametersTemplate<T>(name, value, throwIfNotUsed));
  392. p->m_next.reset(m_next.release());
  393. m_next.reset(p.release());
  394. m_defaultThrowIfNotUsed = throwIfNotUsed;
  395. return *this;
  396. }
  397. //! \brief Appends a NameValuePair to a collection of NameValuePairs
  398. //! \tparam T the class or type
  399. //! \param name the name of the object or value to retrieve
  400. //! \param value reference to a variable that receives the value
  401. template <class T>
  402. AlgorithmParameters & operator()(const char *name, const T &value)
  403. {
  404. return operator()(name, value, m_defaultThrowIfNotUsed);
  405. }
  406. bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
  407. protected:
  408. member_ptr<AlgorithmParametersBase> m_next;
  409. bool m_defaultThrowIfNotUsed;
  410. };
  411. //! \brief Create an object that implements NameValuePairs
  412. //! \tparam T the class or type
  413. //! \param name the name of the object or value to retrieve
  414. //! \param value reference to a variable that receives the value
  415. //! \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed
  416. //! \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(),
  417. //! such as MSVC 7.0 and earlier.
  418. //! \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by
  419. //! repeatedly using \p operator() on the object returned by \p MakeParameters, for example:
  420. //! <pre>
  421. //! AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
  422. //! </pre>
  423. #ifdef __BORLANDC__
  424. typedef AlgorithmParameters MakeParameters;
  425. #else
  426. template <class T>
  427. AlgorithmParameters MakeParameters(const char *name, const T &value, bool throwIfNotUsed = true)
  428. {
  429. return AlgorithmParameters()(name, value, throwIfNotUsed);
  430. }
  431. #endif
  432. #define CRYPTOPP_GET_FUNCTION_ENTRY(name) (Name::name(), &ThisClass::Get##name)
  433. #define CRYPTOPP_SET_FUNCTION_ENTRY(name) (Name::name(), &ThisClass::Set##name)
  434. #define CRYPTOPP_SET_FUNCTION_ENTRY2(name1, name2) (Name::name1(), Name::name2(), &ThisClass::Set##name1##And##name2)
  435. // TODO: fix 6011 when the API/ABI can change
  436. #if (CRYPTOPP_MSC_VERSION >= 1400)
  437. # pragma warning(pop)
  438. #endif
  439. NAMESPACE_END
  440. #endif