utils.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "core/utils.h"
  8. #include "base/qthelp_url.h"
  9. #include "platform/platform_specific.h"
  10. extern "C" {
  11. #include <openssl/crypto.h>
  12. #include <openssl/sha.h>
  13. #include <openssl/err.h>
  14. #include <openssl/evp.h>
  15. #include <openssl/engine.h>
  16. #include <openssl/conf.h>
  17. #include <openssl/ssl.h>
  18. #include <openssl/rand.h>
  19. #include <libavcodec/avcodec.h>
  20. #include <libavformat/avformat.h>
  21. } // extern "C"
  22. #ifdef Q_OS_WIN
  23. #elif defined Q_OS_MAC
  24. #include <mach/mach_time.h>
  25. #else
  26. #include <time.h>
  27. #endif
  28. uint64 _SharedMemoryLocation[4] = { 0x00, 0x01, 0x02, 0x03 };
  29. // Base types compile-time check
  30. static_assert(sizeof(char) == 1, "Basic types size check failed");
  31. static_assert(sizeof(uchar) == 1, "Basic types size check failed");
  32. static_assert(sizeof(int16) == 2, "Basic types size check failed");
  33. static_assert(sizeof(uint16) == 2, "Basic types size check failed");
  34. static_assert(sizeof(int32) == 4, "Basic types size check failed");
  35. static_assert(sizeof(uint32) == 4, "Basic types size check failed");
  36. static_assert(sizeof(int64) == 8, "Basic types size check failed");
  37. static_assert(sizeof(uint64) == 8, "Basic types size check failed");
  38. static_assert(sizeof(float32) == 4, "Basic types size check failed");
  39. static_assert(sizeof(float64) == 8, "Basic types size check failed");
  40. static_assert(sizeof(mtpPrime) == 4, "Basic types size check failed");
  41. static_assert(sizeof(MTPint) == 4, "Basic types size check failed");
  42. static_assert(sizeof(MTPlong) == 8, "Basic types size check failed");
  43. static_assert(sizeof(MTPint128) == 16, "Basic types size check failed");
  44. static_assert(sizeof(MTPint256) == 32, "Basic types size check failed");
  45. static_assert(sizeof(MTPdouble) == 8, "Basic types size check failed");
  46. static_assert(sizeof(int) >= 4, "Basic types size check failed");
  47. // Precise timing functions / rand init
  48. namespace ThirdParty {
  49. void start() {
  50. Platform::ThirdParty::start();
  51. if (!RAND_status()) { // should be always inited in all modern OS
  52. const auto FeedSeed = [](auto value) {
  53. RAND_seed(&value, sizeof(value));
  54. };
  55. #ifdef Q_OS_WIN
  56. LARGE_INTEGER li;
  57. QueryPerformanceFrequency(&li);
  58. FeedSeed(li.QuadPart);
  59. QueryPerformanceCounter(&li);
  60. FeedSeed(li.QuadPart);
  61. #elif defined Q_OS_MAC
  62. mach_timebase_info_data_t tb = { 0 };
  63. mach_timebase_info(&tb);
  64. FeedSeed(tb);
  65. FeedSeed(mach_absolute_time());
  66. #else
  67. timespec ts = { 0 };
  68. clock_gettime(CLOCK_MONOTONIC, &ts);
  69. FeedSeed(ts);
  70. #endif
  71. if (!RAND_status()) {
  72. LOG(("MTP Error: Could not init OpenSSL rand, RAND_status() is 0..."));
  73. }
  74. }
  75. }
  76. void finish() {
  77. #if OPENSSL_VERSION_NUMBER >= 0x30000000L
  78. EVP_default_properties_enable_fips(nullptr, 0);
  79. #else
  80. FIPS_mode_set(0);
  81. #endif
  82. CONF_modules_unload(1);
  83. }
  84. }
  85. int32 *hashSha1(const void *data, uint32 len, void *dest) {
  86. return (int32*)SHA1((const uchar*)data, (size_t)len, (uchar*)dest);
  87. }
  88. int32 *hashSha256(const void *data, uint32 len, void *dest) {
  89. return (int32*)SHA256((const uchar*)data, (size_t)len, (uchar*)dest);
  90. }
  91. // md5 hash, taken somewhere from the internet
  92. namespace {
  93. inline void _md5_decode(uint32 *output, const uchar *input, uint32 len) {
  94. for (uint32 i = 0, j = 0; j < len; i++, j += 4) {
  95. output[i] = ((uint32)input[j]) | (((uint32)input[j + 1]) << 8) | (((uint32)input[j + 2]) << 16) | (((uint32)input[j + 3]) << 24);
  96. }
  97. }
  98. inline void _md5_encode(uchar *output, const uint32 *input, uint32 len) {
  99. for (uint32 i = 0, j = 0; j < len; i++, j += 4) {
  100. output[j + 0] = (input[i]) & 0xFF;
  101. output[j + 1] = (input[i] >> 8) & 0xFF;
  102. output[j + 2] = (input[i] >> 16) & 0xFF;
  103. output[j + 3] = (input[i] >> 24) & 0xFF;
  104. }
  105. }
  106. inline uint32 _md5_rotate_left(uint32 x, int n) {
  107. return (x << n) | (x >> (32 - n));
  108. }
  109. inline uint32 _md5_F(uint32 x, uint32 y, uint32 z) {
  110. return (x & y) | (~x & z);
  111. }
  112. inline uint32 _md5_G(uint32 x, uint32 y, uint32 z) {
  113. return (x & z) | (y & ~z);
  114. }
  115. inline uint32 _md5_H(uint32 x, uint32 y, uint32 z) {
  116. return x ^ y ^ z;
  117. }
  118. inline uint32 _md5_I(uint32 x, uint32 y, uint32 z) {
  119. return y ^ (x | ~z);
  120. }
  121. inline void _md5_FF(uint32 &a, uint32 b, uint32 c, uint32 d, uint32 x, uint32 s, uint32 ac) {
  122. a = _md5_rotate_left(a + _md5_F(b, c, d) + x + ac, s) + b;
  123. }
  124. inline void _md5_GG(uint32 &a, uint32 b, uint32 c, uint32 d, uint32 x, uint32 s, uint32 ac) {
  125. a = _md5_rotate_left(a + _md5_G(b, c, d) + x + ac, s) + b;
  126. }
  127. inline void _md5_HH(uint32 &a, uint32 b, uint32 c, uint32 d, uint32 x, uint32 s, uint32 ac) {
  128. a = _md5_rotate_left(a + _md5_H(b, c, d) + x + ac, s) + b;
  129. }
  130. inline void _md5_II(uint32 &a, uint32 b, uint32 c, uint32 d, uint32 x, uint32 s, uint32 ac) {
  131. a = _md5_rotate_left(a + _md5_I(b, c, d) + x + ac, s) + b;
  132. }
  133. static uchar _md5_padding[64] = {
  134. 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  135. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  136. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  137. };
  138. }
  139. HashMd5::HashMd5(const void *input, uint32 length) : _finalized(false) {
  140. init();
  141. if (input && length > 0) feed(input, length);
  142. }
  143. void HashMd5::feed(const void *input, uint32 length) {
  144. uint32 index = _count[0] / 8 % _md5_block_size;
  145. const uchar *buf = (const uchar *)input;
  146. if ((_count[0] += (length << 3)) < (length << 3)) {
  147. _count[1]++;
  148. }
  149. _count[1] += (length >> 29);
  150. uint32 firstpart = 64 - index;
  151. uint32 i;
  152. if (length >= firstpart) {
  153. memcpy(&_buffer[index], buf, firstpart);
  154. transform(_buffer);
  155. for (i = firstpart; i + _md5_block_size <= length; i += _md5_block_size) {
  156. transform(&buf[i]);
  157. }
  158. index = 0;
  159. } else {
  160. i = 0;
  161. }
  162. memcpy(&_buffer[index], &buf[i], length - i);
  163. }
  164. int32 *HashMd5::result() {
  165. if (!_finalized) finalize();
  166. return (int32*)_digest;
  167. }
  168. void HashMd5::init() {
  169. _count[0] = 0;
  170. _count[1] = 0;
  171. _state[0] = 0x67452301;
  172. _state[1] = 0xefcdab89;
  173. _state[2] = 0x98badcfe;
  174. _state[3] = 0x10325476;
  175. }
  176. void HashMd5::finalize() {
  177. if (!_finalized) {
  178. uchar bits[8];
  179. _md5_encode(bits, _count, 8);
  180. uint32 index = _count[0] / 8 % 64, paddingLen = (index < 56) ? (56 - index) : (120 - index);
  181. feed(_md5_padding, paddingLen);
  182. feed(bits, 8);
  183. _md5_encode(_digest, _state, 16);
  184. _finalized = true;
  185. }
  186. }
  187. void HashMd5::transform(const uchar *block) {
  188. uint32 a = _state[0], b = _state[1], c = _state[2], d = _state[3], x[16];
  189. _md5_decode(x, block, _md5_block_size);
  190. _md5_FF(a, b, c, d, x[0] , 7 , 0xd76aa478);
  191. _md5_FF(d, a, b, c, x[1] , 12, 0xe8c7b756);
  192. _md5_FF(c, d, a, b, x[2] , 17, 0x242070db);
  193. _md5_FF(b, c, d, a, x[3] , 22, 0xc1bdceee);
  194. _md5_FF(a, b, c, d, x[4] , 7 , 0xf57c0faf);
  195. _md5_FF(d, a, b, c, x[5] , 12, 0x4787c62a);
  196. _md5_FF(c, d, a, b, x[6] , 17, 0xa8304613);
  197. _md5_FF(b, c, d, a, x[7] , 22, 0xfd469501);
  198. _md5_FF(a, b, c, d, x[8] , 7 , 0x698098d8);
  199. _md5_FF(d, a, b, c, x[9] , 12, 0x8b44f7af);
  200. _md5_FF(c, d, a, b, x[10], 17, 0xffff5bb1);
  201. _md5_FF(b, c, d, a, x[11], 22, 0x895cd7be);
  202. _md5_FF(a, b, c, d, x[12], 7 , 0x6b901122);
  203. _md5_FF(d, a, b, c, x[13], 12, 0xfd987193);
  204. _md5_FF(c, d, a, b, x[14], 17, 0xa679438e);
  205. _md5_FF(b, c, d, a, x[15], 22, 0x49b40821);
  206. _md5_GG(a, b, c, d, x[1] , 5 , 0xf61e2562);
  207. _md5_GG(d, a, b, c, x[6] , 9 , 0xc040b340);
  208. _md5_GG(c, d, a, b, x[11], 14, 0x265e5a51);
  209. _md5_GG(b, c, d, a, x[0] , 20, 0xe9b6c7aa);
  210. _md5_GG(a, b, c, d, x[5] , 5 , 0xd62f105d);
  211. _md5_GG(d, a, b, c, x[10], 9 , 0x2441453);
  212. _md5_GG(c, d, a, b, x[15], 14, 0xd8a1e681);
  213. _md5_GG(b, c, d, a, x[4] , 20, 0xe7d3fbc8);
  214. _md5_GG(a, b, c, d, x[9] , 5 , 0x21e1cde6);
  215. _md5_GG(d, a, b, c, x[14], 9 , 0xc33707d6);
  216. _md5_GG(c, d, a, b, x[3] , 14, 0xf4d50d87);
  217. _md5_GG(b, c, d, a, x[8] , 20, 0x455a14ed);
  218. _md5_GG(a, b, c, d, x[13], 5 , 0xa9e3e905);
  219. _md5_GG(d, a, b, c, x[2] , 9 , 0xfcefa3f8);
  220. _md5_GG(c, d, a, b, x[7] , 14, 0x676f02d9);
  221. _md5_GG(b, c, d, a, x[12], 20, 0x8d2a4c8a);
  222. _md5_HH(a, b, c, d, x[5] , 4 , 0xfffa3942);
  223. _md5_HH(d, a, b, c, x[8] , 11, 0x8771f681);
  224. _md5_HH(c, d, a, b, x[11], 16, 0x6d9d6122);
  225. _md5_HH(b, c, d, a, x[14], 23, 0xfde5380c);
  226. _md5_HH(a, b, c, d, x[1] , 4 , 0xa4beea44);
  227. _md5_HH(d, a, b, c, x[4] , 11, 0x4bdecfa9);
  228. _md5_HH(c, d, a, b, x[7] , 16, 0xf6bb4b60);
  229. _md5_HH(b, c, d, a, x[10], 23, 0xbebfbc70);
  230. _md5_HH(a, b, c, d, x[13], 4 , 0x289b7ec6);
  231. _md5_HH(d, a, b, c, x[0] , 11, 0xeaa127fa);
  232. _md5_HH(c, d, a, b, x[3] , 16, 0xd4ef3085);
  233. _md5_HH(b, c, d, a, x[6] , 23, 0x4881d05);
  234. _md5_HH(a, b, c, d, x[9] , 4 , 0xd9d4d039);
  235. _md5_HH(d, a, b, c, x[12], 11, 0xe6db99e5);
  236. _md5_HH(c, d, a, b, x[15], 16, 0x1fa27cf8);
  237. _md5_HH(b, c, d, a, x[2] , 23, 0xc4ac5665);
  238. _md5_II(a, b, c, d, x[0] , 6 , 0xf4292244);
  239. _md5_II(d, a, b, c, x[7] , 10, 0x432aff97);
  240. _md5_II(c, d, a, b, x[14], 15, 0xab9423a7);
  241. _md5_II(b, c, d, a, x[5] , 21, 0xfc93a039);
  242. _md5_II(a, b, c, d, x[12], 6 , 0x655b59c3);
  243. _md5_II(d, a, b, c, x[3] , 10, 0x8f0ccc92);
  244. _md5_II(c, d, a, b, x[10], 15, 0xffeff47d);
  245. _md5_II(b, c, d, a, x[1] , 21, 0x85845dd1);
  246. _md5_II(a, b, c, d, x[8] , 6 , 0x6fa87e4f);
  247. _md5_II(d, a, b, c, x[15], 10, 0xfe2ce6e0);
  248. _md5_II(c, d, a, b, x[6] , 15, 0xa3014314);
  249. _md5_II(b, c, d, a, x[13], 21, 0x4e0811a1);
  250. _md5_II(a, b, c, d, x[4] , 6 , 0xf7537e82);
  251. _md5_II(d, a, b, c, x[11], 10, 0xbd3af235);
  252. _md5_II(c, d, a, b, x[2] , 15, 0x2ad7d2bb);
  253. _md5_II(b, c, d, a, x[9] , 21, 0xeb86d391);
  254. _state[0] += a;
  255. _state[1] += b;
  256. _state[2] += c;
  257. _state[3] += d;
  258. }
  259. int32 *hashMd5(const void *data, uint32 len, void *dest) {
  260. HashMd5 md5(data, len);
  261. memcpy(dest, md5.result(), 16);
  262. return (int32*)dest;
  263. }
  264. char *hashMd5Hex(const int32 *hashmd5, void *dest) {
  265. char *md5To = (char*)dest;
  266. const uchar *res = (const uchar*)hashmd5;
  267. for (int i = 0; i < 16; ++i) {
  268. uchar ch(res[i]), high = (ch >> 4) & 0x0F, low = ch & 0x0F;
  269. md5To[i * 2 + 0] = high + ((high > 0x09) ? ('a' - 0x0A) : '0');
  270. md5To[i * 2 + 1] = low + ((low > 0x09) ? ('a' - 0x0A) : '0');
  271. }
  272. return md5To;
  273. }
  274. namespace {
  275. QMap<QString, QString> fastRusEng;
  276. QHash<QChar, QString> fastLetterRusEng;
  277. QMap<uint32, QString> fastDoubleLetterRusEng;
  278. QHash<QChar, QChar> fastRusKeyboardSwitch;
  279. QHash<QChar, QChar> fastUkrKeyboardSwitch;
  280. }
  281. QString translitLetterRusEng(QChar letter, QChar next, int32 &toSkip) {
  282. if (fastDoubleLetterRusEng.isEmpty()) {
  283. fastDoubleLetterRusEng.insert((QString::fromUtf8("Ы").at(0).unicode() << 16) | QString::fromUtf8("й").at(0).unicode(), u"Y"_q);
  284. fastDoubleLetterRusEng.insert((QString::fromUtf8("и").at(0).unicode() << 16) | QString::fromUtf8("я").at(0).unicode(), u"ia"_q);
  285. fastDoubleLetterRusEng.insert((QString::fromUtf8("и").at(0).unicode() << 16) | QString::fromUtf8("й").at(0).unicode(), u"y"_q);
  286. fastDoubleLetterRusEng.insert((QString::fromUtf8("к").at(0).unicode() << 16) | QString::fromUtf8("с").at(0).unicode(), u"x"_q);
  287. fastDoubleLetterRusEng.insert((QString::fromUtf8("ы").at(0).unicode() << 16) | QString::fromUtf8("й").at(0).unicode(), u"y"_q);
  288. fastDoubleLetterRusEng.insert((QString::fromUtf8("ь").at(0).unicode() << 16) | QString::fromUtf8("е").at(0).unicode(), u"ye"_q);
  289. }
  290. QMap<uint32, QString>::const_iterator i = fastDoubleLetterRusEng.constFind((letter.unicode() << 16) | next.unicode());
  291. if (i != fastDoubleLetterRusEng.cend()) {
  292. toSkip = 2;
  293. return i.value();
  294. }
  295. toSkip = 1;
  296. if (fastLetterRusEng.isEmpty()) {
  297. fastLetterRusEng.insert(QString::fromUtf8("А").at(0), u"A"_q);
  298. fastLetterRusEng.insert(QString::fromUtf8("Б").at(0), u"B"_q);
  299. fastLetterRusEng.insert(QString::fromUtf8("В").at(0), u"V"_q);
  300. fastLetterRusEng.insert(QString::fromUtf8("Г").at(0), u"G"_q);
  301. fastLetterRusEng.insert(QString::fromUtf8("Ґ").at(0), u"G"_q);
  302. fastLetterRusEng.insert(QString::fromUtf8("Д").at(0), u"D"_q);
  303. fastLetterRusEng.insert(QString::fromUtf8("Е").at(0), u"E"_q);
  304. fastLetterRusEng.insert(QString::fromUtf8("Є").at(0), u"Ye"_q);
  305. fastLetterRusEng.insert(QString::fromUtf8("Ё").at(0), u"Yo"_q);
  306. fastLetterRusEng.insert(QString::fromUtf8("Ж").at(0), u"Zh"_q);
  307. fastLetterRusEng.insert(QString::fromUtf8("З").at(0), u"Z"_q);
  308. fastLetterRusEng.insert(QString::fromUtf8("И").at(0), u"I"_q);
  309. fastLetterRusEng.insert(QString::fromUtf8("Ї").at(0), u"Yi"_q);
  310. fastLetterRusEng.insert(QString::fromUtf8("І").at(0), u"I"_q);
  311. fastLetterRusEng.insert(QString::fromUtf8("Й").at(0), u"J"_q);
  312. fastLetterRusEng.insert(QString::fromUtf8("К").at(0), u"K"_q);
  313. fastLetterRusEng.insert(QString::fromUtf8("Л").at(0), u"L"_q);
  314. fastLetterRusEng.insert(QString::fromUtf8("М").at(0), u"M"_q);
  315. fastLetterRusEng.insert(QString::fromUtf8("Н").at(0), u"N"_q);
  316. fastLetterRusEng.insert(QString::fromUtf8("О").at(0), u"O"_q);
  317. fastLetterRusEng.insert(QString::fromUtf8("П").at(0), u"P"_q);
  318. fastLetterRusEng.insert(QString::fromUtf8("Р").at(0), u"R"_q);
  319. fastLetterRusEng.insert(QString::fromUtf8("С").at(0), u"S"_q);
  320. fastLetterRusEng.insert(QString::fromUtf8("Т").at(0), u"T"_q);
  321. fastLetterRusEng.insert(QString::fromUtf8("У").at(0), u"U"_q);
  322. fastLetterRusEng.insert(QString::fromUtf8("Ў").at(0), u"W"_q);
  323. fastLetterRusEng.insert(QString::fromUtf8("Ф").at(0), u"F"_q);
  324. fastLetterRusEng.insert(QString::fromUtf8("Х").at(0), u"Kh"_q);
  325. fastLetterRusEng.insert(QString::fromUtf8("Ц").at(0), u"Ts"_q);
  326. fastLetterRusEng.insert(QString::fromUtf8("Ч").at(0), u"Ch"_q);
  327. fastLetterRusEng.insert(QString::fromUtf8("Ш").at(0), u"Sh"_q);
  328. fastLetterRusEng.insert(QString::fromUtf8("Щ").at(0), u"Sch"_q);
  329. fastLetterRusEng.insert(QString::fromUtf8("Э").at(0), u"E"_q);
  330. fastLetterRusEng.insert(QString::fromUtf8("Ю").at(0), u"Yu"_q);
  331. fastLetterRusEng.insert(QString::fromUtf8("Я").at(0), u"Ya"_q);
  332. fastLetterRusEng.insert(QString::fromUtf8("Ў").at(0), u"W"_q);
  333. fastLetterRusEng.insert(QString::fromUtf8("а").at(0), u"a"_q);
  334. fastLetterRusEng.insert(QString::fromUtf8("б").at(0), u"b"_q);
  335. fastLetterRusEng.insert(QString::fromUtf8("в").at(0), u"v"_q);
  336. fastLetterRusEng.insert(QString::fromUtf8("г").at(0), u"g"_q);
  337. fastLetterRusEng.insert(QString::fromUtf8("ґ").at(0), u"g"_q);
  338. fastLetterRusEng.insert(QString::fromUtf8("д").at(0), u"d"_q);
  339. fastLetterRusEng.insert(QString::fromUtf8("е").at(0), u"e"_q);
  340. fastLetterRusEng.insert(QString::fromUtf8("є").at(0), u"ye"_q);
  341. fastLetterRusEng.insert(QString::fromUtf8("ё").at(0), u"yo"_q);
  342. fastLetterRusEng.insert(QString::fromUtf8("ж").at(0), u"zh"_q);
  343. fastLetterRusEng.insert(QString::fromUtf8("з").at(0), u"z"_q);
  344. fastLetterRusEng.insert(QString::fromUtf8("й").at(0), u"y"_q);
  345. fastLetterRusEng.insert(QString::fromUtf8("ї").at(0), u"yi"_q);
  346. fastLetterRusEng.insert(QString::fromUtf8("і").at(0), u"i"_q);
  347. fastLetterRusEng.insert(QString::fromUtf8("л").at(0), u"l"_q);
  348. fastLetterRusEng.insert(QString::fromUtf8("м").at(0), u"m"_q);
  349. fastLetterRusEng.insert(QString::fromUtf8("н").at(0), u"n"_q);
  350. fastLetterRusEng.insert(QString::fromUtf8("о").at(0), u"o"_q);
  351. fastLetterRusEng.insert(QString::fromUtf8("п").at(0), u"p"_q);
  352. fastLetterRusEng.insert(QString::fromUtf8("р").at(0), u"r"_q);
  353. fastLetterRusEng.insert(QString::fromUtf8("с").at(0), u"s"_q);
  354. fastLetterRusEng.insert(QString::fromUtf8("т").at(0), u"t"_q);
  355. fastLetterRusEng.insert(QString::fromUtf8("у").at(0), u"u"_q);
  356. fastLetterRusEng.insert(QString::fromUtf8("ў").at(0), u"w"_q);
  357. fastLetterRusEng.insert(QString::fromUtf8("ф").at(0), u"f"_q);
  358. fastLetterRusEng.insert(QString::fromUtf8("х").at(0), u"kh"_q);
  359. fastLetterRusEng.insert(QString::fromUtf8("ц").at(0), u"ts"_q);
  360. fastLetterRusEng.insert(QString::fromUtf8("ч").at(0), u"ch"_q);
  361. fastLetterRusEng.insert(QString::fromUtf8("ш").at(0), u"sh"_q);
  362. fastLetterRusEng.insert(QString::fromUtf8("щ").at(0), u"sch"_q);
  363. fastLetterRusEng.insert(QString::fromUtf8("ъ").at(0), QString());
  364. fastLetterRusEng.insert(QString::fromUtf8("э").at(0), u"e"_q);
  365. fastLetterRusEng.insert(QString::fromUtf8("ю").at(0), u"yu"_q);
  366. fastLetterRusEng.insert(QString::fromUtf8("я").at(0), u"ya"_q);
  367. fastLetterRusEng.insert(QString::fromUtf8("ў").at(0), u"w"_q);
  368. fastLetterRusEng.insert(QString::fromUtf8("Ы").at(0), u"Y"_q);
  369. fastLetterRusEng.insert(QString::fromUtf8("и").at(0), u"i"_q);
  370. fastLetterRusEng.insert(QString::fromUtf8("к").at(0), u"k"_q);
  371. fastLetterRusEng.insert(QString::fromUtf8("ы").at(0), u"y"_q);
  372. fastLetterRusEng.insert(QString::fromUtf8("ь").at(0), QString());
  373. }
  374. QHash<QChar, QString>::const_iterator j = fastLetterRusEng.constFind(letter);
  375. if (j != fastLetterRusEng.cend()) {
  376. return j.value();
  377. }
  378. return QString(1, letter);
  379. }
  380. QString translitRusEng(const QString &rus) {
  381. if (fastRusEng.isEmpty()) {
  382. fastRusEng.insert(QString::fromUtf8("Александр"), u"Alexander"_q);
  383. fastRusEng.insert(QString::fromUtf8("александр"), u"alexander"_q);
  384. fastRusEng.insert(QString::fromUtf8("Филипп"), u"Philip"_q);
  385. fastRusEng.insert(QString::fromUtf8("филипп"), u"philip"_q);
  386. fastRusEng.insert(QString::fromUtf8("Пётр"), u"Petr"_q);
  387. fastRusEng.insert(QString::fromUtf8("пётр"), u"petr"_q);
  388. fastRusEng.insert(QString::fromUtf8("Гай"), u"Gai"_q);
  389. fastRusEng.insert(QString::fromUtf8("гай"), u"gai"_q);
  390. fastRusEng.insert(QString::fromUtf8("Ильин"), u"Ilyin"_q);
  391. fastRusEng.insert(QString::fromUtf8("ильин"), u"ilyin"_q);
  392. }
  393. QMap<QString, QString>::const_iterator i = fastRusEng.constFind(rus);
  394. if (i != fastRusEng.cend()) {
  395. return i.value();
  396. }
  397. QString result;
  398. result.reserve(rus.size() * 2);
  399. int32 toSkip = 0;
  400. for (QString::const_iterator i = rus.cbegin(), e = rus.cend(); i != e; i += toSkip) {
  401. result += translitLetterRusEng(*i, (i + 1 == e) ? ' ' : *(i + 1), toSkip);
  402. }
  403. return result;
  404. }
  405. QString engAlphabet = "qwertyuiop[]asdfghjkl;'zxcvbnm,.";
  406. QString engAlphabetUpper = engAlphabet.toUpper();
  407. void initializeKeyboardSwitch() {
  408. if (fastRusKeyboardSwitch.isEmpty()) {
  409. QString rusAlphabet = "йцукенгшщзхъфывапролджэячсмитьбю";
  410. QString rusAlphabetUpper = rusAlphabet.toUpper();
  411. for (int i = 0; i < rusAlphabet.size(); ++i) {
  412. fastRusKeyboardSwitch.insert(engAlphabetUpper[i], rusAlphabetUpper[i]);
  413. fastRusKeyboardSwitch.insert(engAlphabet[i], rusAlphabet[i]);
  414. fastRusKeyboardSwitch.insert(rusAlphabetUpper[i], engAlphabetUpper[i]);
  415. fastRusKeyboardSwitch.insert(rusAlphabet[i], engAlphabet[i]);
  416. }
  417. }
  418. if (fastUkrKeyboardSwitch.isEmpty()) {
  419. QString ukrAlphabet = "йцукенгшщзхїфівапролджєячсмитьбю";
  420. QString ukrAlphabetUpper = ukrAlphabet.toUpper();
  421. for (int i = 0; i < ukrAlphabet.size(); ++i) {
  422. fastUkrKeyboardSwitch.insert(engAlphabetUpper[i], ukrAlphabetUpper[i]);
  423. fastUkrKeyboardSwitch.insert(engAlphabet[i], ukrAlphabet[i]);
  424. fastUkrKeyboardSwitch.insert(ukrAlphabetUpper[i], engAlphabetUpper[i]);
  425. fastUkrKeyboardSwitch.insert(ukrAlphabet[i], engAlphabet[i]);
  426. }
  427. }
  428. }
  429. QString switchKeyboardLayout(const QString& from, QHash<QChar, QChar>& keyboardSwitch) {
  430. QString result;
  431. result.reserve(from.size());
  432. for (QString::const_iterator i = from.cbegin(), e = from.cend(); i != e; ++i) {
  433. QHash<QChar, QChar>::const_iterator j = keyboardSwitch.constFind(*i);
  434. if (j == keyboardSwitch.cend()) {
  435. result += *i;
  436. } else {
  437. result += j.value();
  438. }
  439. }
  440. return result;
  441. }
  442. QString rusKeyboardLayoutSwitch(const QString& from) {
  443. initializeKeyboardSwitch();
  444. QString rus = switchKeyboardLayout(from, fastRusKeyboardSwitch);
  445. QString ukr = switchKeyboardLayout(from, fastUkrKeyboardSwitch);
  446. return rus == ukr ? rus : rus + ' ' + ukr;
  447. }