Advertisement
Guest User

Untitled

a guest
Mar 18th, 2017
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.52 KB | None | 0 0
  1. #ifndef THORS_ANVIL_MYSQL_PACKAGE_READER_H
  2. #define THORS_ANVIL_MYSQL_PACKAGE_READER_H
  3.  
  4. #include "MySQLTimeBag.h"
  5. #include "ThorSQL/SQLUtil.h"
  6. #include <memory>
  7. #include <functional>
  8. #include <vector>
  9. #include <map>
  10. #include <string>
  11. #include <ctime>
  12.  
  13. #include "MySQLConfig.h"
  14. #if defined(THOR_ENDIAN_SML)
  15. #define THOR_MYSQL_READ_INT(into, len) stream.read(reinterpret_cast<char*>(&into), len)
  16. #elif defined(THOR_ENDIAN_BIG)
  17. #error Have not defined this for large endian systems.
  18. #else
  19. #error Unknow Endianess
  20. #endif
  21.  
  22. namespace ThorsAnvil
  23. {
  24. namespace MySQL
  25. {
  26.  
  27. class PackageStream;
  28. class RespPackage;
  29. class RespPackageEOF;
  30.  
  31. class ConectReader
  32. {
  33. PackageStream& stream;
  34. unsigned long capbil;
  35. unsigned long charset;
  36.  
  37. unsigned long long lengthEncodedIntegerUsingSize(unsigned char size);
  38. public:
  39. using OKAction = std::function<RespPackage*(int byte, ConectReader&)>;
  40. using OKMap = std::map<int, OKAction>;
  41. ConectReader(PackageStream& stream)
  42. : stream(stream)
  43. , capbil(0)
  44. , charset(0)
  45. {}
  46.  
  47. void initFromHandshake(unsigned long capabilities, unsigned long charset);
  48. std::unique_ptr<RespPackageEOF> recvMessageEOF();
  49. std::unique_ptr<RespPackage> recvMessage(OKMap const& actions = {});
  50. public:
  51.  
  52.  
  53. void read(char* data, std::size_t len);
  54. bool isEmpty() const;
  55.  
  56. unsigned long getCapabilities() {return capbil;}
  57. template<int len>
  58. unsigned long long fixedLengthInteger(unsigned long rCap) {return (rCap & capbil) ? fixedLengthInteger<len>() : 0;}
  59. unsigned long long lengthEncodedInteger(unsigned long rCap) {return (rCap & capbil) ? lengthEncodedInteger() : 0;}
  60. std::string fixedLengthString(std::size_t s, unsigned long rCap) {return (rCap & capbil) ? fixedLengthString(s) : "";}
  61. std::string nulTerminatedString(unsigned long rCap) {return (rCap & capbil) ? nulTerminatedString() : "";}
  62. std::string variableLengthString(std::size_t s, unsigned long rCap) {return (rCap & capbil) ? variableLengthString(s) : "";}
  63. std::string lengthEncodedString(unsigned long rCap) {return (rCap & capbil) ? lengthEncodedString() : "";}
  64. std::string restOfPacketString(unsigned long rCap) {return (rCap & capbil) ? restOfPacketString() : "";}
  65.  
  66. template<int len>
  67. unsigned long long fixedLengthInteger();
  68. unsigned long long lengthEncodedInteger();
  69. std::string fixedLengthString(std::size_t size);
  70. std::string nulTerminatedString();
  71. std::string variableLengthString(std::size_t size);
  72. std::string lengthEncodedString();
  73. std::string restOfPacketString();
  74.  
  75. std::vector<char> lengthEncodedBlob();
  76. std::time_t readDate();
  77. std::time_t readRel();
  78. unsigned long long readRelMicro();
  79. MySQLTimeBag readDateIntoTimeBag();
  80. MySQLTimeBag readTimeIntoTimeBag();
  81.  
  82. void drop();
  83. void reset();
  84. };
  85.  
  86.  
  87. }
  88. }
  89.  
  90. #ifndef COVERAGE_MySQL
  91. #include "ConectReader.tpp"
  92. #endif
  93.  
  94. #endif
  95.  
  96. #ifndef THORS_ANVIL_MYSQL_PACKAGE_WRITER_H
  97. #define THORS_ANVIL_MYSQL_PACKAGE_WRITER_H
  98.  
  99. #include <string>
  100. #include <vector>
  101. #include <ctime>
  102.  
  103. #include "MySQLConfig.h"
  104. #if defined(THOR_ENDIAN_SML)
  105. #define THOR_MYSQL_WRITE_INT(from, len) stream.write(reinterpret_cast<char const*>(&from), len)
  106. #elif defined(THOR_ENDIAN_BIG)
  107. #error Have not defined this for large endian systems.
  108. #else
  109. #error Unknow Endianess
  110. #endif
  111.  
  112. namespace ThorsAnvil
  113. {
  114. namespace MySQL
  115. {
  116.  
  117. class PackageStream;
  118.  
  119. class ConectWriter
  120. {
  121. protected:
  122. PackageStream& stream;
  123. unsigned long capabilities;
  124. unsigned long charset;
  125.  
  126. public:
  127.  
  128. ConectWriter(PackageStream& stream)
  129. : stream(stream)
  130. , capabilities(0)
  131. , charset(0)
  132. {}
  133. virtual ~ConectWriter() {}
  134.  
  135. void initFromHandshake(unsigned long capabilities, unsigned long charset);
  136.  
  137. template<int len>
  138. void writeFixedLengthInteger(unsigned long long value);
  139. void writeLengthEncodedInteger(unsigned long long value);
  140. void writeFixedLengthString(std::string const& value, std::size_t size); // Makes sure the string is correct size
  141. void writeNullTerminatedString(std::string const& value); // Adds NULL terminator
  142. void writeVariableLengthString(std::string const& value); // Not NULL terminated.
  143. void writeLengthEncodedString(std::string const& value);
  144.  
  145. void writeRawData(char const* buffer, std::size_t size);
  146.  
  147. void writeLengthEncodedBlob(std::vector<char> const& value);
  148. void writeDate(std::time_t const& value);
  149. void writeRel(std::time_t const& value);
  150. void writeRel(unsigned long long value);
  151.  
  152. void flush();
  153. void reset();
  154. };
  155.  
  156. }
  157. }
  158.  
  159. #ifndef COVERAGE_MySQL
  160. #include "ConectWriter.tpp"
  161. #endif
  162.  
  163. #endif
  164.  
  165. #include "PackageStream.h"
  166.  
  167. namespace ThorsAnvil
  168. {
  169. namespace MySQL
  170. {
  171.  
  172. template<int len>
  173. inline unsigned long long ConectReader::fixedLengthInteger()
  174. {
  175. unsigned long long result = 0;
  176. THOR_MYSQL_READ_INT(result, len);
  177.  
  178. return result;
  179. }
  180.  
  181.  
  182. }
  183. }
  184.  
  185. #include "PackageStream.h"
  186.  
  187. namespace ThorsAnvil
  188. {
  189. namespace MySQL
  190. {
  191.  
  192. template<int len>
  193. void ConectWriter::writeFixedLengthInteger(unsigned long long value)
  194. {
  195. THOR_MYSQL_WRITE_INT(value, len);
  196. }
  197.  
  198. }
  199. }
  200.  
  201. #include "PackageStream.h"
  202. #include "ConectReader.h"
  203. #include "RespPackageOK.h"
  204. #include "RespPackageEOF.h"
  205. #include "RespPackageERR.h"
  206.  
  207. using namespace ThorsAnvil::MySQL;
  208.  
  209. void ConectReader::initFromHandshake(unsigned long newCapabilities, unsigned long newCharset)
  210. {
  211. capbil = newCapabilities;
  212. charset = newCharset;
  213. }
  214.  
  215. void ConectReader::read(char* data, std::size_t len)
  216. {
  217. stream.read(data, len);
  218. }
  219.  
  220. bool ConectReader::isEmpty() const
  221. {
  222. return stream.isEmpty();
  223. }
  224.  
  225. std::unique_ptr<RespPackageEOF> ConectReader::recvMessageEOF()
  226. {
  227. std::unique_ptr<RespPackage> result = recvMessage({{0xFE, [](int firstByte, ConectReader& reader){return new RespPackageEOF(firstByte, reader);}}});
  228. return downcastUniquePtr<RespPackageEOF>(std::move(result));
  229. }
  230.  
  231. std::unique_ptr<RespPackage> ConectReader::recvMessage(OKMap const& actions /*= {}*/)
  232. {
  233. int packageType = fixedLengthInteger<1>();;
  234. auto find = actions.find(packageType);
  235. if (find != actions.end())
  236. {
  237. return std::unique_ptr<RespPackage>(find->second(packageType, *this));
  238. }
  239. else if (packageType == 0x00)
  240. {
  241. return std::unique_ptr<RespPackage>(new RespPackageOK(packageType, *this));
  242. }
  243. else if (packageType == 0xFE)
  244. {
  245. // EOF default action: => read and ignore.
  246. RespPackageEOF eofPackage(packageType, *this);
  247. return nullptr;
  248. }
  249. else if (packageType == 0xFF)
  250. {
  251. // Error default action: => read and throw
  252. RespPackageERR errorPackage(packageType, *this);
  253. throw std::runtime_error(
  254. errorMsg("ThorsAnvil::MySQL::ConectReader::recvMessage: ", "Error Message from Server: ", errorPackage.message()
  255. ));
  256. }
  257. else
  258. {
  259. find = actions.find(-1);
  260. if (find != actions.end())
  261. {
  262. return std::unique_ptr<RespPackage>(find->second(packageType, *this));
  263. }
  264. throw std::domain_error(
  265. errorMsg("ThorsAnvil::MySQL::ConectReader::recvMessage: ", "Unknown Result Type: ", packageType));
  266. }
  267. }
  268.  
  269. unsigned long long ConectReader::lengthEncodedInteger()
  270. {
  271. unsigned char type;
  272. read(reinterpret_cast<char*>(&type), 1);
  273. return lengthEncodedIntegerUsingSize(type);
  274. }
  275.  
  276. unsigned long long ConectReader::lengthEncodedIntegerUsingSize(unsigned char type)
  277. {
  278. unsigned long result;
  279. switch (type)
  280. {
  281. case 0xFA:
  282. case 0xFB:
  283. case 0xFF:
  284. throw std::domain_error(
  285. errorMsg("ThorsAnvil::MySQL::ConectReader::lengthEncodedInteger: ", "Invalid length encoding: ", type));
  286. case 0xFC: result = fixedLengthInteger<2>(); break;
  287. case 0xFD: result = fixedLengthInteger<3>(); break;
  288. case 0xFE: result = fixedLengthInteger<8>(); break;
  289. default: result = type;
  290. }
  291. return result;
  292. }
  293.  
  294. std::string ConectReader::fixedLengthString(std::size_t size)
  295. {
  296. std::string result(size, ' ');
  297. read(&result[0], size);
  298. return result;
  299. }
  300.  
  301. std::string ConectReader::nulTerminatedString()
  302. {
  303. std::string result;
  304. char x;
  305.  
  306. for (read(&x, 1); x != ''; read(&x, 1))
  307. {
  308. result.append(1, x);
  309. }
  310. return result;
  311. }
  312.  
  313. std::string ConectReader::variableLengthString(std::size_t size)
  314. {
  315. return fixedLengthString(size);
  316. }
  317.  
  318. std::string ConectReader::lengthEncodedString()
  319. {
  320. unsigned long size = lengthEncodedInteger();
  321. std::string result(size, '');
  322. read(&result[0], size);
  323. return result;
  324. }
  325.  
  326. std::string ConectReader::restOfPacketString()
  327. {
  328. return stream.readRemainingData();
  329. }
  330.  
  331. std::vector<char> ConectReader::lengthEncodedBlob()
  332. {
  333. long size = lengthEncodedInteger();
  334. std::vector<char> result(size, '');
  335. read(&result[0], size);
  336. return result;
  337. }
  338. std::time_t ConectReader::readDate()
  339. {
  340. MySQLTimeBag timeBag = readDateIntoTimeBag();
  341. tm time;
  342.  
  343. time.tm_sec = timeBag.second;
  344. time.tm_min = timeBag.minute;
  345. time.tm_hour = timeBag.hour;
  346. time.tm_mday = timeBag.day;
  347. time.tm_mon = timeBag.month - 1;
  348. time.tm_year = timeBag.year - 1900;
  349. time.tm_isdst = false;
  350. time.tm_zone = NULL;
  351. time.tm_gmtoff = 0;
  352.  
  353. return timegm(&time);
  354. }
  355.  
  356. MySQLTimeBag ConectReader::readDateIntoTimeBag()
  357. {
  358. MySQLTimeBag timeBag;
  359. long size = fixedLengthInteger<1>();
  360. if (size != 11 && size != 7 && size != 4 && size != 0)
  361. {
  362. throw std::domain_error(
  363. errorMsg("ThorsAnvil::MySQL::ConectReader::readDate: ", "Invalid Date Size", size, "nExpecting: 11/7/4/0"));
  364. }
  365. if (size == 11 || size == 7 || size == 4)
  366. {
  367. timeBag.year = fixedLengthInteger<2>();
  368. timeBag.month = fixedLengthInteger<1>();
  369. timeBag.day = fixedLengthInteger<1>();
  370. }
  371. if (size == 11 || size == 7)
  372. {
  373. timeBag.hour = fixedLengthInteger<1>();
  374. timeBag.minute = fixedLengthInteger<1>();
  375. timeBag.second = fixedLengthInteger<1>();
  376. }
  377. if (size == 11)
  378. {
  379. timeBag.uSecond = fixedLengthInteger<4>();
  380. }
  381. return timeBag;
  382. }
  383.  
  384. std::time_t ConectReader::readRel()
  385. {
  386. MySQLTimeBag timeBag = readTimeIntoTimeBag();
  387. return timeBag.day * (60LL*60*24) + timeBag.hour * (60LL*60) + timeBag.minute * (60LL) + timeBag.second;
  388. }
  389. unsigned long long ConectReader::readRelMicro()
  390. {
  391. MySQLTimeBag timeBag = readTimeIntoTimeBag();
  392. return timeBag.day * (1000LL*60*60*24)
  393. + timeBag.hour * (1000LL*60*60)
  394. + timeBag.minute * (1000LL*60)
  395. + timeBag.second * (1000LL)
  396. + timeBag.uSecond;
  397. }
  398. MySQLTimeBag ConectReader::readTimeIntoTimeBag()
  399. {
  400. MySQLTimeBag timeBag;
  401. long size = fixedLengthInteger<1>();
  402. if (size != 12 && size != 8 && size != 0)
  403. {
  404. throw std::domain_error(
  405. errorMsg("ThorsAnvil::MySQL::ConectReader::readTime: ", "Invalid Time Size: ", size, "nExpecting 12/8/0"));
  406. }
  407. timeBag.type = MySQLTimeBag::RelativePositive;
  408. if (size == 12 || size == 8)
  409. {
  410. long negativeTest = fixedLengthInteger<1>();
  411. if (negativeTest < 0 || negativeTest > 1)
  412. {
  413. throw std::domain_error( errorMsg("ThorsAnvil::MySQL::ConectReader::readTime: ", "Invalid Negative Test"));
  414. }
  415. if (negativeTest == 1)
  416. {
  417. timeBag.type = MySQLTimeBag::RelativeNegative;
  418. }
  419. timeBag.day = fixedLengthInteger<4>();
  420. timeBag.hour = fixedLengthInteger<1>();
  421. timeBag.minute = fixedLengthInteger<1>();
  422. timeBag.second = fixedLengthInteger<1>();
  423. }
  424. if (size == 12)
  425. {
  426. timeBag.uSecond = fixedLengthInteger<4>();
  427. }
  428. return timeBag;
  429. }
  430.  
  431. void ConectReader::drop()
  432. {
  433. stream.drop();
  434. }
  435.  
  436. void ConectReader::reset()
  437. {
  438. stream.reset();
  439. }
  440.  
  441. #include "PackageStream.h"
  442. #include "ConectWriter.h"
  443.  
  444. using namespace ThorsAnvil::MySQL;
  445.  
  446. void ConectWriter::initFromHandshake(unsigned long newCapabilities, unsigned long newCharset)
  447. {
  448. capabilities = newCapabilities;
  449. charset = newCharset;
  450. }
  451.  
  452. void ConectWriter::writeLengthEncodedInteger(unsigned long long value)
  453. {
  454. /*
  455. * Length encoded integers.
  456. * Val < 251 => 1bytes
  457. * Val >= 251 < 2^16 => 0Xfc + 2byte Value
  458. * Val >= 2^16 < 2^24 => 0Xfd + 3byte Value
  459. * Val >= 2^24 < 2^64 => 0Xfe + 8byte Value
  460. */
  461. static char const mark2Byte = 'xFC';
  462. static char const mark3Byte = 'xFD';
  463. static char const mark8Byte = 'xFE';
  464.  
  465. if (value < 251) { writeFixedLengthInteger<1>(value);}
  466. else if (value <= 0xFFFF) { stream.write(&mark2Byte, 1); writeFixedLengthInteger<2>(value);}
  467. else if (value <= 0xFFFFFF) { stream.write(&mark3Byte, 1); writeFixedLengthInteger<3>(value);}
  468. else { stream.write(&mark8Byte, 1); writeFixedLengthInteger<8>(value);}
  469. }
  470.  
  471. void ConectWriter::writeFixedLengthString(std::string const& value, std::size_t size)
  472. {
  473. std::string output(value);
  474. output.resize(size);
  475. writeVariableLengthString(output);
  476. }
  477.  
  478. void ConectWriter::writeNullTerminatedString(std::string const& value)
  479. {
  480. stream.write(value.c_str(), value.size() + 1);
  481. }
  482.  
  483. void ConectWriter::writeVariableLengthString(std::string const& value)
  484. {
  485. stream.write(&value[0], value.size());
  486. }
  487.  
  488. void ConectWriter::writeLengthEncodedString(std::string const& value)
  489. {
  490. writeLengthEncodedInteger(value.size());
  491. writeVariableLengthString(value);
  492. }
  493.  
  494. void ConectWriter::writeRawData(char const* buffer, std::size_t size)
  495. {
  496. stream.write(buffer, size);
  497. }
  498.  
  499. void ConectWriter::writeLengthEncodedBlob(std::vector<char> const& value)
  500. {
  501. writeLengthEncodedInteger(value.size());
  502. stream.write(&value[0], value.size());
  503. }
  504.  
  505. void ConectWriter::writeDate(std::time_t const& )
  506. {
  507. }
  508.  
  509. void ConectWriter::writeRel(std::time_t const& )
  510. {
  511. }
  512.  
  513. void ConectWriter::writeRel(unsigned long long )
  514. {
  515. }
  516.  
  517. void ConectWriter::flush()
  518. {
  519. stream.flush();
  520. }
  521. void ConectWriter::reset()
  522. {
  523. stream.startNewConversation();
  524. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement