mtproto_dump_to_text.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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 "mtproto/details/mtproto_dump_to_text.h"
  8. #include "scheme-dump_to_text.h"
  9. #include "scheme.h"
  10. #include <zlib.h>
  11. namespace MTP::details {
  12. bool DumpToTextCore(DumpToTextBuffer &to, const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons, uint32 level, mtpPrime vcons) {
  13. switch (mtpTypeId(cons)) {
  14. case mtpc_int: {
  15. MTPint value;
  16. if (value.read(from, end, cons)) {
  17. to.add(QString::number(value.v)).add(" [INT]");
  18. return true;
  19. }
  20. } break;
  21. case mtpc_long: {
  22. MTPlong value;
  23. if (value.read(from, end, cons)) {
  24. to.add(QString::number(value.v)).add(" [LONG]");
  25. return true;
  26. }
  27. } break;
  28. case mtpc_int128: {
  29. MTPint128 value;
  30. if (value.read(from, end, cons)) {
  31. to.add(QString::number(value.h)).add(" * 2^64 + ").add(QString::number(value.l)).add(" [INT128]");
  32. return true;
  33. }
  34. } break;
  35. case mtpc_int256: {
  36. MTPint256 value;
  37. if (value.read(from, end, cons)) {
  38. to.add(QString::number(value.h.h)).add(" * 2^192 + ").add(QString::number(value.h.l)).add(" * 2^128 + ").add(QString::number(value.l.h)).add(" * 2 ^ 64 + ").add(QString::number(value.l.l)).add(" [INT256]");
  39. return true;
  40. }
  41. } break;
  42. case mtpc_double: {
  43. MTPdouble value;
  44. if (value.read(from, end, cons)) {
  45. to.add(QString::number(value.v)).add(" [DOUBLE]");
  46. return true;
  47. }
  48. } break;
  49. case mtpc_string: {
  50. MTPstring value;
  51. if (value.read(from, end, cons)) {
  52. auto strUtf8 = value.v;
  53. auto str = QString::fromUtf8(strUtf8);
  54. if (str.toUtf8() == strUtf8) {
  55. to.add("\"").add(str.replace('\\', "\\\\").replace('"', "\\\"").replace('\n', "\\n")).add("\" [STRING]");
  56. } else if (strUtf8.size() < 64) {
  57. to.add(Logs::mb(strUtf8.constData(), strUtf8.size()).str()).add(" [").add(QString::number(strUtf8.size())).add(" BYTES]");
  58. } else {
  59. to.add(Logs::mb(strUtf8.constData(), 16).str()).add("... [").add(QString::number(strUtf8.size())).add(" BYTES]");
  60. }
  61. return true;
  62. }
  63. } break;
  64. case mtpc_vector: {
  65. if (from < end) {
  66. int32 cnt = *(from++);
  67. to.add("[ vector<0x").add(QString::number(vcons, 16)).add("> (").add(QString::number(cnt)).add(")");
  68. if (cnt) {
  69. to.add("\n").addSpaces(level);
  70. for (int32 i = 0; i < cnt; ++i) {
  71. to.add(" ");
  72. if (!DumpToTextType(to, from, end, vcons, level + 1)) {
  73. return false;
  74. }
  75. to.add(",\n").addSpaces(level);
  76. }
  77. } else {
  78. to.add(" ");
  79. }
  80. to.add("]");
  81. return true;
  82. }
  83. } break;
  84. case mtpc_gzip_packed: {
  85. MTPstring packed;
  86. // read packed string as serialized mtp string type
  87. if (!packed.read(from, end)) {
  88. return false;
  89. }
  90. uint32 packedLen = packed.v.size(), unpackedChunk = packedLen;
  91. mtpBuffer result; // * 4 because of mtpPrime type
  92. result.resize(0);
  93. z_stream stream;
  94. stream.zalloc = nullptr;
  95. stream.zfree = nullptr;
  96. stream.opaque = nullptr;
  97. stream.avail_in = 0;
  98. stream.next_in = nullptr;
  99. int res = inflateInit2(&stream, 16 + MAX_WBITS);
  100. if (res != Z_OK) {
  101. return false;
  102. }
  103. stream.avail_in = packedLen;
  104. stream.next_in = reinterpret_cast<Bytef*>(packed.v.data());
  105. stream.avail_out = 0;
  106. while (!stream.avail_out) {
  107. result.resize(result.size() + unpackedChunk);
  108. stream.avail_out = unpackedChunk * sizeof(mtpPrime);
  109. stream.next_out = (Bytef*)&result[result.size() - unpackedChunk];
  110. int res = inflate(&stream, Z_NO_FLUSH);
  111. if (res != Z_OK && res != Z_STREAM_END) {
  112. inflateEnd(&stream);
  113. return false;
  114. }
  115. }
  116. if (stream.avail_out & 0x03) {
  117. return false;
  118. }
  119. result.resize(result.size() - (stream.avail_out >> 2));
  120. inflateEnd(&stream);
  121. if (result.empty()) {
  122. return false;
  123. }
  124. const mtpPrime *newFrom = result.constData(), *newEnd = result.constData() + result.size();
  125. to.add("[GZIPPED] ");
  126. return DumpToTextType(to, newFrom, newEnd, 0, level);
  127. } break;
  128. default: {
  129. for (uint32 i = 1; i < mtpLayerMaxSingle; ++i) {
  130. if (cons == mtpLayers[i]) {
  131. to.add("[LAYER").add(QString::number(i + 1)).add("] ");
  132. return DumpToTextType(to, from, end, 0, level);
  133. }
  134. }
  135. if (cons == mtpc_invokeWithLayer) {
  136. if (from >= end) {
  137. return false;
  138. }
  139. int32 layer = *(from++);
  140. to.add("[LAYER").add(QString::number(layer)).add("] ");
  141. return DumpToTextType(to, from, end, 0, level);
  142. }
  143. } break;
  144. }
  145. return false;
  146. }
  147. QString DumpToText(const mtpPrime *&from, const mtpPrime *end) {
  148. DumpToTextBuffer to;
  149. [[maybe_unused]] bool result = DumpToTextType(to, from, end, mtpc_core_message);
  150. return QString::fromUtf8(to.p, to.size);
  151. }
  152. } // namespace MTP::details