PageRenderTime 67ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/share/qtcreator/dumper/dumper.cpp

https://bitbucket.org/kpozn/qt-creator-py-reborn
C++ | 3812 lines | 3347 code | 262 blank | 203 comment | 479 complexity | 06d9224422c78910876a1048c0151946 MD5 | raw file
Possible License(s): LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /**************************************************************************
  2. **
  3. ** This file is part of Qt Creator
  4. **
  5. ** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
  6. **
  7. ** Contact: Nokia Corporation (qt-info@nokia.com)
  8. **
  9. **
  10. ** GNU Lesser General Public License Usage
  11. **
  12. ** This file may be used under the terms of the GNU Lesser General Public
  13. ** License version 2.1 as published by the Free Software Foundation and
  14. ** appearing in the file LICENSE.LGPL included in the packaging of this file.
  15. ** Please review the following information to ensure the GNU Lesser General
  16. ** Public License version 2.1 requirements will be met:
  17. ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  18. **
  19. ** In addition, as a special exception, Nokia gives you certain additional
  20. ** rights. These rights are described in the Nokia Qt LGPL Exception
  21. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  22. **
  23. ** Other Usage
  24. **
  25. ** Alternatively, this file may be used in accordance with the terms and
  26. ** conditions contained in a signed written agreement between you and Nokia.
  27. **
  28. ** If you have questions regarding the use of this file, please contact
  29. ** Nokia at qt-info@nokia.com.
  30. **
  31. **************************************************************************/
  32. #include <qglobal.h>
  33. #if USE_QT_CORE
  34. #include <QDateTime>
  35. #include <QDebug>
  36. #include <QDir>
  37. #include <QFile>
  38. #include <QFileInfo>
  39. #include <QHash>
  40. #include <QLinkedList>
  41. #include <QList>
  42. #include <QQueue>
  43. #include <QLocale>
  44. #include <QMap>
  45. #include <QMetaEnum>
  46. #include <QMetaObject>
  47. #include <QMetaProperty>
  48. #include <QPoint>
  49. #include <QPointF>
  50. #include <QPointer>
  51. #include <QRect>
  52. #include <QRectF>
  53. #include <QStack>
  54. #include <QSize>
  55. #include <QSizeF>
  56. #include <QString>
  57. #include <QStringList>
  58. #include <QTextCodec>
  59. #include <QTextStream>
  60. #include <QVector>
  61. #ifndef QT_BOOTSTRAPPED
  62. #include <QModelIndex>
  63. #if QT_VERSION >= 0x040500
  64. #include <QSharedPointer>
  65. #include <QSharedDataPointer>
  66. #include <QSharedData>
  67. #include <QWeakPointer>
  68. #endif
  69. #ifndef USE_QT_GUI
  70. # ifdef QT_GUI_LIB
  71. # define USE_QT_GUI 1
  72. # endif
  73. #endif
  74. #ifndef USE_QT_WIDGETS
  75. # if defined(QT_WIDGETS_LIB) || ((QT_VERSION < 0x050000) && defined(USE_QT_GUI))
  76. # define USE_QT_WIDGETS 1
  77. # endif
  78. #endif
  79. #ifdef USE_QT_GUI
  80. # include <QImage>
  81. # include <QRegion>
  82. # include <QPixmap>
  83. # include <QFont>
  84. # include <QColor>
  85. # include <QKeySequence>
  86. #endif
  87. #ifdef USE_QT_WIDGETS
  88. # include <QSizePolicy>
  89. # include <QWidget>
  90. # include <QApplication>
  91. #endif
  92. #endif // QT_BOOTSTRAPPED
  93. #endif // USE_QT_CORE
  94. #ifdef Q_OS_WIN
  95. # include <windows.h>
  96. #endif
  97. #include <list>
  98. #include <map>
  99. #include <string>
  100. #include <set>
  101. #include <vector>
  102. #include <stdio.h>
  103. #ifdef QT_BOOTSTRAPPED
  104. # define NS ""
  105. # define NSX "'"
  106. # define NSY "'"
  107. #else
  108. # include "dumper_p.h"
  109. #endif // QT_BOOTSTRAPPED
  110. #if QT_VERSION >= 0x050000
  111. # define MAP_WORKS 0
  112. #else
  113. # define MAP_WORKS 1
  114. #endif
  115. int qtGhVersion = QT_VERSION;
  116. /*!
  117. \class QDumper
  118. \brief Helper class for producing "nice" output in Qt Creator's debugger.
  119. \internal
  120. The whole "custom dumper" implementation is currently far less modular
  121. than it could be. But as the code is still in a flux, making it nicer
  122. from a pure archtectural point of view seems still be a waste of resources.
  123. Some hints:
  124. New dumpers for non-templated classes should be mentioned in
  125. \c{qDumpObjectData440()} in the \c{protocolVersion == 1} branch.
  126. Templated classes need extra support on the IDE level
  127. (see plugins/debugger/gdbengine.cpp) and should not be mentiond in
  128. \c{qDumpObjectData440()}.
  129. In any case, dumper processesing should end up in
  130. \c{handleProtocolVersion2and3()} and needs an entry in the big switch there.
  131. Next step is to create a suitable \c{static void qDumpFoo(QDumper &d)}
  132. function. At the bare minimum it should contain something like this:
  133. \c{
  134. const Foo &foo = *reinterpret_cast<const Foo *>(d.data);
  135. d.putItem("value", ...);
  136. d.putItem("type", "Foo");
  137. d.putItem("numchild", "0");
  138. }
  139. 'd.putItem(name, value)' roughly expands to:
  140. d.put((name)).put("=\"").put(value).put("\"";
  141. Useful (i.e. understood by the IDE) names include:
  142. \list
  143. \o "name" shows up in the first column in the Locals&Watchers view.
  144. \o "value" shows up in the second column.
  145. \o "valueencoded" should be set to "1" if the value is base64 encoded.
  146. Always base64-encode values that might use unprintable or otherwise
  147. "confuse" the protocol (like spaces and quotes). [A-Za-z0-9] is "safe".
  148. A value of "3" is used for base64-encoded UCS4, "2" denotes
  149. base64-encoded UTF16.
  150. \o "numchild" return the number of children in the view. Effectively, only
  151. 0 and != 0 will be used, so don't try too hard to get the number right.
  152. \endlist
  153. If the current item has children, it might be queried to produce information
  154. about these children. In this case the dumper should use something like this:
  155. \c{
  156. if (d.dumpChildren) {
  157. d.beginChildren();
  158. [...]
  159. d.endChildren();
  160. }
  161. */
  162. #if defined(QT_BEGIN_NAMESPACE)
  163. QT_BEGIN_NAMESPACE
  164. #endif
  165. const char *stdStringTypeC = "std::basic_string<char,std::char_traits<char>,std::allocator<char> >";
  166. const char *stdWideStringTypeUShortC = "std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >";
  167. #if defined(QT_BEGIN_NAMESPACE)
  168. QT_END_NAMESPACE
  169. #endif
  170. // This can be mangled typenames of nested templates, each char-by-char
  171. // comma-separated integer list...
  172. // The output buffer.
  173. #ifdef MACROSDEBUG
  174. Q_DECL_EXPORT char xDumpInBuffer[10000];
  175. Q_DECL_EXPORT char xDumpOutBuffer[1000000];
  176. # define inBuffer xDumpInBuffer
  177. # define outBuffer xDumpOutBuffer
  178. #else
  179. Q_DECL_EXPORT char qDumpInBuffer[10000];
  180. Q_DECL_EXPORT char qDumpOutBuffer[1000000];
  181. # define inBuffer qDumpInBuffer
  182. # define outBuffer qDumpOutBuffer
  183. #endif
  184. namespace {
  185. static QByteArray strPtrConst = "* const";
  186. static bool isPointerType(const QByteArray &type)
  187. {
  188. return type.endsWith('*') || type.endsWith(strPtrConst);
  189. }
  190. static QByteArray stripPointerType(const QByteArray &_type)
  191. {
  192. QByteArray type = _type;
  193. if (type.endsWith('*'))
  194. type.chop(1);
  195. if (type.endsWith(strPtrConst))
  196. type.chop(7);
  197. if (type.endsWith(' '))
  198. type.chop(1);
  199. return type;
  200. }
  201. // This is used to abort evaluation of custom data dumpers in a "coordinated"
  202. // way. Abortion will happen at the latest when we try to access a non-initialized
  203. // non-trivial object, so there is no way to prevent this from occurring at all
  204. // conceptually. Gdb will catch SIGSEGV and return to the calling frame.
  205. // This is just fine provided we only _read_ memory in the custom handlers below.
  206. // We don't use this code for MSVC/CDB anymore.
  207. volatile int qProvokeSegFaultHelper;
  208. static const void *addOffset(const void *p, int offset)
  209. {
  210. return offset + reinterpret_cast<const char *>(p);
  211. }
  212. static const void *deref(const void *p)
  213. {
  214. return *reinterpret_cast<const char* const*>(p);
  215. }
  216. #if USE_QT_CORE
  217. static const void *skipvtable(const void *p)
  218. {
  219. return sizeof(void *) + reinterpret_cast<const char *>(p);
  220. }
  221. static const void *dfunc(const void *p)
  222. {
  223. return deref(skipvtable(p));
  224. }
  225. #endif
  226. static bool isEqual(const char *s, const char *t)
  227. {
  228. return qstrcmp(s, t) == 0;
  229. }
  230. static bool startsWith(const char *s, const char *t)
  231. {
  232. while (char c = *t++)
  233. if (c != *s++)
  234. return false;
  235. return true;
  236. }
  237. // Check memory for read access and provoke segfault if nothing else helps.
  238. // On Windows, try to be less crash-prone by checking memory using WinAPI
  239. #ifdef Q_OS_WIN
  240. # define qCheckAccess(d) do { \
  241. if (IsBadReadPtr(d, 1)) \
  242. return; \
  243. qProvokeSegFaultHelper = *(char*)d; \
  244. } while (0)
  245. # define qCheckPointer(d) do { \
  246. if (d && IsBadReadPtr(d, 1)) \
  247. return; \
  248. if (d) qProvokeSegFaultHelper = *(char*)d; \
  249. } while (0)
  250. #else
  251. # define qCheckAccess(d) do { \
  252. if (!couldBePointer(d) && d != 0) \
  253. return; \
  254. qProvokeSegFaultHelper = *(char*)d; \
  255. } while (0)
  256. # define qCheckPointer(d) do { \
  257. if (!couldBePointer(d)) \
  258. return; \
  259. if (d) \
  260. qProvokeSegFaultHelper = *(char*)d; \
  261. } while (0)
  262. static bool couldBePointer(const void *p)
  263. {
  264. // we assume valid pointer to be 4-aligned at least.
  265. // So use this check only when this is guaranteed.
  266. // FIXME: this breaks e.g. in the QString dumper...
  267. const quintptr d = quintptr(p);
  268. //qDebug() << "CHECKING : " << p << ((d & 3) == 0 && (d > 1000 || d == 0));
  269. //return (d & 3) == 0 && (d > 1000 || d == 0);
  270. return d > 1000 || d == 0;
  271. }
  272. #endif
  273. #ifdef QT_NAMESPACE
  274. const char *stripNamespace(const char *type)
  275. {
  276. static const size_t nslen = strlen(NS);
  277. return startsWith(type, NS) ? type + nslen : type;
  278. }
  279. #else
  280. inline const char *stripNamespace(const char *type)
  281. {
  282. return type;
  283. }
  284. #endif
  285. static bool isSimpleType(const char *type)
  286. {
  287. switch (type[0]) {
  288. case 'c':
  289. return isEqual(type, "char");
  290. case 'd':
  291. return isEqual(type, "double");
  292. case 'f':
  293. return isEqual(type, "float");
  294. case 'i':
  295. return isEqual(type, "int");
  296. case 'l':
  297. return isEqual(type, "long") || startsWith(type, "long ");
  298. case 's':
  299. return isEqual(type, "short") || startsWith(type, "short ")
  300. || isEqual(type, "signed") || startsWith(type, "signed ");
  301. case 'u':
  302. return isEqual(type, "unsigned") || startsWith(type, "unsigned ");
  303. }
  304. return false;
  305. }
  306. static bool isStringType(const char *type)
  307. {
  308. return isEqual(type, NS "QString")
  309. || isEqual(type, NS "QByteArray")
  310. || isEqual(type, "std::string")
  311. || isEqual(type, "std::wstring")
  312. || isEqual(type, "wstring");
  313. }
  314. #if USE_QT_CORE
  315. static bool isMovableType(const char *type)
  316. {
  317. if (isPointerType(type))
  318. return true;
  319. if (isSimpleType(type))
  320. return true;
  321. type = stripNamespace(type);
  322. switch (type[1]) {
  323. case 'B':
  324. return isEqual(type, "QBrush")
  325. || isEqual(type, "QBitArray")
  326. || isEqual(type, "QByteArray") ;
  327. case 'C':
  328. return isEqual(type, "QCustomTypeInfo")
  329. || isEqual(type, "QChar");
  330. case 'D':
  331. return isEqual(type, "QDate")
  332. || isEqual(type, "QDateTime");
  333. case 'F':
  334. return isEqual(type, "QFileInfo")
  335. || isEqual(type, "QFixed")
  336. || isEqual(type, "QFixedPoint")
  337. || isEqual(type, "QFixedSize");
  338. case 'H':
  339. return isEqual(type, "QHashDummyValue");
  340. case 'I':
  341. return isEqual(type, "QIcon")
  342. || isEqual(type, "QImage");
  343. case 'L':
  344. return isEqual(type, "QLine")
  345. || isEqual(type, "QLineF")
  346. || isEqual(type, "QLatin1Char")
  347. || isEqual(type, "QLocal");
  348. case 'M':
  349. return isEqual(type, "QMatrix")
  350. || isEqual(type, "QModelIndex");
  351. case 'P':
  352. return isEqual(type, "QPoint")
  353. || isEqual(type, "QPointF")
  354. || isEqual(type, "QPen")
  355. || isEqual(type, "QPersistentModelIndex");
  356. case 'R':
  357. return isEqual(type, "QResourceRoot")
  358. || isEqual(type, "QRect")
  359. || isEqual(type, "QRectF")
  360. || isEqual(type, "QRegExp");
  361. case 'S':
  362. return isEqual(type, "QSize")
  363. || isEqual(type, "QSizeF")
  364. || isEqual(type, "QString");
  365. case 'T':
  366. return isEqual(type, "QTime")
  367. || isEqual(type, "QTextBlock");
  368. case 'U':
  369. return isEqual(type, "QUrl");
  370. case 'V':
  371. return isEqual(type, "QVariant");
  372. case 'X':
  373. return isEqual(type, "QXmlStreamAttribute")
  374. || isEqual(type, "QXmlStreamNamespaceDeclaration")
  375. || isEqual(type, "QXmlStreamNotationDeclaration")
  376. || isEqual(type, "QXmlStreamEntityDeclaration");
  377. }
  378. return false;
  379. }
  380. #endif
  381. struct QDumper
  382. {
  383. explicit QDumper();
  384. ~QDumper();
  385. // direct write to the output
  386. QDumper &put(long c);
  387. QDumper &put(int i);
  388. QDumper &put(double d);
  389. QDumper &put(float d);
  390. QDumper &put(unsigned long c);
  391. QDumper &put(unsigned int i);
  392. QDumper &put(const void *p);
  393. QDumper &put(qulonglong c);
  394. QDumper &put(long long c);
  395. QDumper &put(const char *str);
  396. QDumper &put(const QByteArray &ba);
  397. QDumper &put(const QString &str);
  398. QDumper &put(char c);
  399. // convienience functions for writing key="value" pairs:
  400. template <class Value>
  401. void putItem(const char *name, const Value &value)
  402. {
  403. putCommaIfNeeded();
  404. put(name).put('=').put('"').put(value).put('"');
  405. }
  406. void putItem(const char *name, const char *value, const char *setvalue)
  407. {
  408. if (!isEqual(value, setvalue))
  409. putItem(name, value);
  410. }
  411. // convienience functions for writing typical properties.
  412. // roughly equivalent to
  413. // beginHash();
  414. // putItem("name", name);
  415. // putItem("value", value);
  416. // putItem("type", NS "QString");
  417. // putItem("numchild", "0");
  418. // putItem("valueencoded", "2");
  419. // endHash();
  420. void putHash(const char *name, const QString &value);
  421. void putHash(const char *name, const QByteArray &value);
  422. void putHash(const char *name, int value);
  423. void putHash(const char *name, long value);
  424. void putHash(const char *name, bool value);
  425. void putHash(const char *name, QChar value);
  426. void putHash(const char *name, float value);
  427. void putHash(const char *name, double value);
  428. void putStringValue(const QString &value);
  429. void beginHash(); // start of data hash output
  430. void endHash(); // start of data hash output
  431. void beginChildren(const char *mainInnerType = 0); // start of children list
  432. void endChildren(); // end of children list
  433. void beginItem(const char *name); // start of named item, ready to accept value
  434. void endItem(); // end of named item, used after value output is complete
  435. // convenience for putting "<n items>"
  436. void putItemCount(const char *name, int count);
  437. // convenience for putting "<>n items>" (more than X items)
  438. void putTruncatedItemCount(const char *name, int count);
  439. void putCommaIfNeeded();
  440. // convienience function for writing the last item of an abbreviated list
  441. void putEllipsis();
  442. void disarm();
  443. void putBase64Encoded(const char *buf, int n);
  444. void checkFill();
  445. // the dumper arguments
  446. int protocolVersion; // dumper protocol version
  447. int token; // some token to show on success
  448. const char *outerType; // object type
  449. const char *iname; // object name used for display
  450. const char *exp; // object expression
  451. const char *innerType; // 'inner type' for class templates
  452. const void *data; // pointer to raw data
  453. bool dumpChildren; // do we want to see children?
  454. // handling of nested templates
  455. void setupTemplateParameters();
  456. enum { maxTemplateParameters = 10 };
  457. const char *templateParameters[maxTemplateParameters + 1];
  458. // internal state
  459. int extraInt[4];
  460. bool success; // are we finished?
  461. bool full;
  462. int pos;
  463. const char *currentChildType;
  464. const char *currentChildNumChild;
  465. };
  466. QDumper::QDumper()
  467. {
  468. success = false;
  469. full = false;
  470. outBuffer[0] = 'f'; // marks output as 'wrong'
  471. pos = 1;
  472. currentChildType = 0;
  473. currentChildNumChild = 0;
  474. }
  475. QDumper::~QDumper()
  476. {
  477. outBuffer[pos++] = '\0';
  478. if (success)
  479. outBuffer[0] = (full ? '+' : 't');
  480. }
  481. void QDumper::setupTemplateParameters()
  482. {
  483. char *s = const_cast<char *>(innerType);
  484. int templateParametersCount = 1;
  485. templateParameters[0] = s;
  486. for (int i = 1; i != maxTemplateParameters + 1; ++i)
  487. templateParameters[i] = 0;
  488. while (*s) {
  489. while (*s && *s != '@')
  490. ++s;
  491. if (*s) {
  492. *s = '\0';
  493. ++s;
  494. templateParameters[templateParametersCount++] = s;
  495. }
  496. }
  497. while (templateParametersCount < maxTemplateParameters)
  498. templateParameters[templateParametersCount++] = 0;
  499. }
  500. QDumper &QDumper::put(char c)
  501. {
  502. checkFill();
  503. if (!full)
  504. outBuffer[pos++] = c;
  505. return *this;
  506. }
  507. QDumper &QDumper::put(unsigned long long c)
  508. {
  509. checkFill();
  510. pos += sprintf(outBuffer + pos, "%llu", c);
  511. return *this;
  512. }
  513. QDumper &QDumper::put(long long c)
  514. {
  515. checkFill();
  516. pos += sprintf(outBuffer + pos, "%lld", c);
  517. return *this;
  518. }
  519. QDumper &QDumper::put(unsigned long c)
  520. {
  521. checkFill();
  522. pos += sprintf(outBuffer + pos, "%lu", c);
  523. return *this;
  524. }
  525. QDumper &QDumper::put(float d)
  526. {
  527. checkFill();
  528. pos += sprintf(outBuffer + pos, "%f", d);
  529. return *this;
  530. }
  531. QDumper &QDumper::put(double d)
  532. {
  533. checkFill();
  534. pos += sprintf(outBuffer + pos, "%f", d);
  535. return *this;
  536. }
  537. QDumper &QDumper::put(unsigned int i)
  538. {
  539. checkFill();
  540. pos += sprintf(outBuffer + pos, "%u", i);
  541. return *this;
  542. }
  543. QDumper &QDumper::put(long c)
  544. {
  545. checkFill();
  546. pos += sprintf(outBuffer + pos, "%ld", c);
  547. return *this;
  548. }
  549. QDumper &QDumper::put(int i)
  550. {
  551. checkFill();
  552. pos += sprintf(outBuffer + pos, "%d", i);
  553. return *this;
  554. }
  555. QDumper &QDumper::put(const void *p)
  556. {
  557. if (p) {
  558. // Pointer is 'long long' on WIN_64, only
  559. static const char *printFormat = sizeof(void *) == sizeof(long) ? "0x%lx" : "0x%llx";
  560. pos += sprintf(outBuffer + pos, printFormat, p);
  561. } else {
  562. pos += sprintf(outBuffer + pos, "<null>");
  563. }
  564. return *this;
  565. }
  566. QDumper &QDumper::put(const char *str)
  567. {
  568. if (!str)
  569. return put("<null>");
  570. while (*str)
  571. put(*(str++));
  572. return *this;
  573. }
  574. QDumper &QDumper::put(const QByteArray &ba)
  575. {
  576. putBase64Encoded(ba.constData(), ba.size());
  577. return *this;
  578. }
  579. QDumper &QDumper::put(const QString &str)
  580. {
  581. putBase64Encoded((const char *)str.constData(), 2 * str.size());
  582. return *this;
  583. }
  584. void QDumper::checkFill()
  585. {
  586. if (pos >= int(sizeof(outBuffer)) - 100)
  587. full = true;
  588. }
  589. void QDumper::putCommaIfNeeded()
  590. {
  591. if (pos == 0)
  592. return;
  593. char c = outBuffer[pos - 1];
  594. if (c == '}' || c == '"' || c == ']')
  595. put(',');
  596. }
  597. void QDumper::putBase64Encoded(const char *buf, int n)
  598. {
  599. const char alphabet[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
  600. "ghijklmn" "opqrstuv" "wxyz0123" "456789+/";
  601. const char padchar = '=';
  602. int padlen = 0;
  603. //int tmpsize = ((n * 4) / 3) + 3;
  604. int i = 0;
  605. while (i < n) {
  606. int chunk = 0;
  607. chunk |= int(uchar(buf[i++])) << 16;
  608. if (i == n) {
  609. padlen = 2;
  610. } else {
  611. chunk |= int(uchar(buf[i++])) << 8;
  612. if (i == n)
  613. padlen = 1;
  614. else
  615. chunk |= int(uchar(buf[i++]));
  616. }
  617. int j = (chunk & 0x00fc0000) >> 18;
  618. int k = (chunk & 0x0003f000) >> 12;
  619. int l = (chunk & 0x00000fc0) >> 6;
  620. int m = (chunk & 0x0000003f);
  621. put(alphabet[j]);
  622. put(alphabet[k]);
  623. put(padlen > 1 ? padchar : alphabet[l]);
  624. put(padlen > 0 ? padchar : alphabet[m]);
  625. }
  626. }
  627. void QDumper::putStringValue(const QString &str)
  628. {
  629. if (str.isNull()) {
  630. beginItem("value");
  631. putBase64Encoded("\"\" (null)", 9);
  632. endItem();
  633. putItem("valueencoded", "5");
  634. } else {
  635. putItem("value", str);
  636. putItem("valueencoded", "2");
  637. }
  638. }
  639. void QDumper::disarm()
  640. {
  641. success = true;
  642. }
  643. void QDumper::beginHash()
  644. {
  645. putCommaIfNeeded();
  646. put('{');
  647. }
  648. void QDumper::endHash()
  649. {
  650. put('}');
  651. }
  652. void QDumper::putEllipsis()
  653. {
  654. putCommaIfNeeded();
  655. put("{name=\"<incomplete>\",value=\"\",type=\"").put(innerType).put("\"}");
  656. }
  657. void QDumper::putItemCount(const char *name, int count)
  658. {
  659. putCommaIfNeeded();
  660. put(name).put("=\"<").put(count).put(" items>\"");
  661. }
  662. void QDumper::putTruncatedItemCount(const char *name, int count)
  663. {
  664. putCommaIfNeeded();
  665. put(name).put("=\"<>").put(count).put(" items>\"");
  666. }
  667. //
  668. // Some helpers to keep the dumper code short
  669. //
  670. void QDumper::beginItem(const char *name)
  671. {
  672. putCommaIfNeeded();
  673. put(name).put('=').put('"');
  674. }
  675. void QDumper::endItem()
  676. {
  677. put('"');
  678. }
  679. void QDumper::beginChildren(const char *mainInnerType)
  680. {
  681. if (mainInnerType) {
  682. putItem("childtype", mainInnerType);
  683. currentChildType = mainInnerType;
  684. if (isSimpleType(mainInnerType) || isStringType(mainInnerType)) {
  685. putItem("childnumchild", "0");
  686. currentChildNumChild = "0";
  687. } else if (isPointerType(mainInnerType)) {
  688. putItem("childnumchild", "1");
  689. currentChildNumChild = "1";
  690. }
  691. }
  692. putCommaIfNeeded();
  693. put("children=[");
  694. }
  695. void QDumper::endChildren()
  696. {
  697. put(']');
  698. currentChildType = 0;
  699. currentChildNumChild = 0;
  700. }
  701. // simple string property
  702. void QDumper::putHash(const char *name, const QString &value)
  703. {
  704. beginHash();
  705. putItem("name", name);
  706. putStringValue(value);
  707. putItem("type", NS "QString");
  708. putItem("numchild", "0");
  709. endHash();
  710. }
  711. void QDumper::putHash(const char *name, const QByteArray &value)
  712. {
  713. beginHash();
  714. putItem("name", name);
  715. putItem("value", value);
  716. putItem("type", NS "QByteArray");
  717. putItem("numchild", "0");
  718. putItem("valueencoded", "1");
  719. endHash();
  720. }
  721. // simple integer property
  722. void QDumper::putHash(const char *name, int value)
  723. {
  724. beginHash();
  725. putItem("name", name);
  726. putItem("value", value);
  727. putItem("type", "int");
  728. putItem("numchild", "0");
  729. endHash();
  730. }
  731. void QDumper::putHash(const char *name, long value)
  732. {
  733. beginHash();
  734. putItem("name", name);
  735. putItem("value", value);
  736. putItem("type", "long");
  737. putItem("numchild", "0");
  738. endHash();
  739. }
  740. void QDumper::putHash(const char *name, float value)
  741. {
  742. beginHash();
  743. putItem("name", name);
  744. putItem("value", value);
  745. putItem("type", "float");
  746. putItem("numchild", "0");
  747. endHash();
  748. }
  749. void QDumper::putHash(const char *name, double value)
  750. {
  751. beginHash();
  752. putItem("name", name);
  753. putItem("value", value);
  754. putItem("type", "double");
  755. putItem("numchild", "0");
  756. endHash();
  757. }
  758. // simple boolean property
  759. void QDumper::putHash(const char *name, bool value)
  760. {
  761. beginHash();
  762. putItem("name", name);
  763. putItem("value", (value ? "true" : "false"));
  764. putItem("type", "bool");
  765. putItem("numchild", "0");
  766. endHash();
  767. }
  768. // a single QChar
  769. void QDumper::putHash(const char *name, QChar value)
  770. {
  771. beginHash();
  772. putItem("name", name);
  773. putStringValue(QString(QLatin1String("'%1' (%2, 0x%3)"))
  774. .arg(value).arg(value.unicode()).arg(value.unicode(), 0, 16));
  775. putItem("type", NS "QChar");
  776. putItem("numchild", "0");
  777. endHash();
  778. }
  779. #define DUMPUNKNOWN_MESSAGE "<not in scope>"
  780. static void qDumpUnknown(QDumper &d, const char *why = 0)
  781. {
  782. if (!why)
  783. why = DUMPUNKNOWN_MESSAGE;
  784. d.putItem("value", why);
  785. d.putItem("valueeditable", "false");
  786. d.putItem("valueenabled", "false");
  787. d.putItem("numchild", "0", d.currentChildNumChild);
  788. d.disarm();
  789. }
  790. static void qDumpStdStringValue(QDumper &d, const std::string &str)
  791. {
  792. d.beginItem("value");
  793. d.putBase64Encoded(str.c_str(), str.size());
  794. d.endItem();
  795. d.putItem("valueencoded", "1");
  796. d.putItem("type", "std::string");
  797. d.putItem("numchild", "0", d.currentChildNumChild);
  798. }
  799. static void qDumpStdWStringValue(QDumper &d, const std::wstring &str)
  800. {
  801. d.beginItem("value");
  802. d.putBase64Encoded((const char *)str.c_str(), str.size() * sizeof(wchar_t));
  803. d.endItem();
  804. d.putItem("valueencoded", (sizeof(wchar_t) == 2 ? "2" : "3"));
  805. d.putItem("type", "std::wstring", d.currentChildType);
  806. d.putItem("numchild", "0", d.currentChildNumChild);
  807. }
  808. // Called by templates, so, not static.
  809. static void qDumpInnerQCharValue(QDumper &d, QChar c, const char *field)
  810. {
  811. char buf[30];
  812. sprintf(buf, "'?', ucs=%d", c.unicode());
  813. if (c.isPrint() && c.unicode() < 127)
  814. buf[1] = char(c.unicode());
  815. d.putCommaIfNeeded();
  816. d.putItem(field, buf);
  817. d.putItem("numchild", "0", d.currentChildNumChild);
  818. }
  819. static void qDumpInnerCharValue(QDumper &d, char c, const char *field)
  820. {
  821. char buf[30];
  822. sprintf(buf, "'?', ascii=%d", c);
  823. if (QChar(QLatin1Char(c)).isPrint() && c < 127)
  824. buf[1] = c;
  825. d.putCommaIfNeeded();
  826. d.putItem(field, buf);
  827. d.putItem("numchild", "0", d.currentChildNumChild);
  828. }
  829. void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr,
  830. const char *field = "value")
  831. {
  832. type = stripNamespace(type);
  833. switch (type[1]) {
  834. case 'h':
  835. if (isEqual(type, "char"))
  836. qDumpInnerCharValue(d, *(char *)addr, field);
  837. break;
  838. case 'l':
  839. if (isEqual(type, "float"))
  840. d.putItem(field, *(float*)addr);
  841. break;
  842. case 'n':
  843. if (isEqual(type, "int"))
  844. d.putItem(field, *(int*)addr);
  845. else if (isEqual(type, "unsigned") || isEqual(type, "unsigned int"))
  846. d.putItem(field, *(unsigned int*)addr);
  847. else if (isEqual(type, "unsigned char"))
  848. qDumpInnerCharValue(d, *(char *)addr, field);
  849. else if (isEqual(type, "unsigned long"))
  850. d.putItem(field, *(unsigned long*)addr);
  851. else if (isEqual(type, "unsigned long long"))
  852. d.putItem(field, *(qulonglong*)addr);
  853. break;
  854. case 'o':
  855. if (isEqual(type, "bool")) {
  856. switch (*(unsigned char*)addr) {
  857. case 0: d.putItem(field, "false"); break;
  858. case 1: d.putItem(field, "true"); break;
  859. default: d.putItem(field, *(unsigned char*)addr); break;
  860. }
  861. } else if (isEqual(type, "double"))
  862. d.putItem(field, *(double*)addr);
  863. else if (isEqual(type, "long"))
  864. d.putItem(field, *(long*)addr);
  865. else if (isEqual(type, "long long"))
  866. d.putItem(field, *(qulonglong*)addr);
  867. break;
  868. case 'B':
  869. if (isEqual(type, "QByteArray")) {
  870. d.putCommaIfNeeded();
  871. d.put(field).put("encoded=\"1\",");
  872. d.putItem(field, *(QByteArray*)addr);
  873. }
  874. break;
  875. case 'C':
  876. if (isEqual(type, "QChar"))
  877. qDumpInnerQCharValue(d, *(QChar*)addr, field);
  878. break;
  879. case 'L':
  880. if (startsWith(type, "QList<")) {
  881. const QListData *ldata = reinterpret_cast<const QListData*>(addr);
  882. d.putItemCount("value", ldata->size());
  883. d.putItem("valueeditable", "false");
  884. d.putItem("numchild", ldata->size());
  885. }
  886. break;
  887. case 'O':
  888. # ifndef QT_BOOTSTRAPPED
  889. if (isEqual(type, "QObject *")) {
  890. if (addr) {
  891. const QObject *ob = reinterpret_cast<const QObject *>(addr);
  892. d.putItem("addr", ob);
  893. d.putItem("value", ob->objectName());
  894. d.putItem("valueencoded", "2");
  895. d.putItem("type", NS "QObject");
  896. d.putItem("displayedtype", ob->metaObject()->className());
  897. d.putItem("numchild", 1);
  898. } else {
  899. d.putItem("value", "0x0");
  900. d.putItem("type", NS "QObject *");
  901. d.putItem("numchild", 0);
  902. }
  903. }
  904. # endif
  905. break;
  906. case 'S':
  907. if (isEqual(type, "QString")) {
  908. d.putCommaIfNeeded();
  909. d.putItem(field, *(QString*)addr);
  910. d.put(',').put(field).put("encoded=\"2\"");
  911. }
  912. break;
  913. case 't':
  914. if (isEqual(type, "std::string")
  915. || isEqual(type, stdStringTypeC)) {
  916. d.putCommaIfNeeded();
  917. qDumpStdStringValue(d, *reinterpret_cast<const std::string*>(addr));
  918. } else if (isEqual(type, "std::wstring")
  919. || isEqual(type, stdWideStringTypeUShortC)) {
  920. qDumpStdWStringValue(d, *reinterpret_cast<const std::wstring*>(addr));
  921. }
  922. break;
  923. default:
  924. break;
  925. }
  926. }
  927. #if USE_QT_CORE
  928. static void qDumpInnerValue(QDumper &d, const char *type, const void *addr)
  929. {
  930. d.putItem("addr", addr);
  931. d.putItem("type", type, d.currentChildType);
  932. if (!type[0])
  933. return;
  934. return qDumpInnerValueHelper(d, type, addr);
  935. }
  936. #endif
  937. static void qDumpInnerValueOrPointer(QDumper &d,
  938. const char *type, const char *strippedtype, const void *addr)
  939. {
  940. if (strippedtype) {
  941. if (deref(addr)) {
  942. d.putItem("addr", deref(addr));
  943. d.putItem("type", strippedtype, d.currentChildType);
  944. qDumpInnerValueHelper(d, strippedtype, deref(addr));
  945. } else {
  946. d.putItem("addr", addr);
  947. d.putItem("type", strippedtype);
  948. d.putItem("value", "<null>");
  949. d.putItem("numchild", "0");
  950. }
  951. } else {
  952. d.putItem("addr", addr);
  953. d.putItem("type", type, d.currentChildType);
  954. qDumpInnerValueHelper(d, type, addr);
  955. }
  956. }
  957. //////////////////////////////////////////////////////////////////////////////
  958. #if USE_QT_CORE
  959. #ifndef QT_BOOTSTRAPPED
  960. struct ModelIndex { int r; int c; void *p; void *m; };
  961. static void qDumpQAbstractItem(QDumper &d)
  962. {
  963. QModelIndex mi;
  964. {
  965. ModelIndex *mm = reinterpret_cast<ModelIndex *>(&mi);
  966. memset(&mi, 0, sizeof(mi));
  967. static const char *printFormat = sizeof(void *) == sizeof(long) ?
  968. "%d,%d,0x%lx,0x%lx" : "%d,%d,0x%llx,0x%llx";
  969. sscanf(d.templateParameters[0], printFormat, &mm->r, &mm->c, &mm->p, &mm->m);
  970. }
  971. const QAbstractItemModel *m = mi.model();
  972. const int rowCount = m->rowCount(mi);
  973. if (rowCount < 0)
  974. return;
  975. const int columnCount = m->columnCount(mi);
  976. if (columnCount < 0)
  977. return;
  978. d.putItem("type", NS "QAbstractItem");
  979. d.beginItem("addr");
  980. d.put('$').put(mi.row()).put(',').put(mi.column()).put(',')
  981. .put(mi.internalPointer()).put(',').put(mi.model());
  982. d.endItem();
  983. //d.putItem("value", "(").put(rowCount).put(",").put(columnCount).put(")");
  984. d.putItem("value", m->data(mi, Qt::DisplayRole).toString());
  985. d.putItem("valueencoded", "2");
  986. d.putItem("numchild", rowCount * columnCount);
  987. if (d.dumpChildren) {
  988. d.beginChildren();
  989. for (int row = 0; row < rowCount; ++row) {
  990. for (int column = 0; column < columnCount; ++column) {
  991. QModelIndex child = m->index(row, column, mi);
  992. d.beginHash();
  993. d.beginItem("name");
  994. d.put("[").put(row).put(",").put(column).put("]");
  995. d.endItem();
  996. //d.putItem("numchild", (m->hasChildren(child) ? "1" : "0"));
  997. d.putItem("numchild", m->rowCount(child) * m->columnCount(child));
  998. d.beginItem("addr");
  999. d.put("$").put(child.row()).put(",").put(child.column()).put(",")
  1000. .put(child.internalPointer()).put(",").put(child.model());
  1001. d.endItem();
  1002. d.putItem("type", NS "QAbstractItem");
  1003. d.putItem("value", m->data(child, Qt::DisplayRole).toString());
  1004. d.putItem("valueencoded", "2");
  1005. d.endHash();
  1006. }
  1007. }
  1008. /*
  1009. d.beginHash();
  1010. d.putItem("name", "DisplayRole");
  1011. d.putItem("numchild", 0);
  1012. d.putItem("value", m->data(mi, Qt::DisplayRole).toString());
  1013. d.putItem("valueencoded", 2);
  1014. d.putItem("type", NS "QString");
  1015. d.endHash();
  1016. */
  1017. d.endChildren();
  1018. }
  1019. d.disarm();
  1020. }
  1021. static void qDumpQAbstractItemModel(QDumper &d)
  1022. {
  1023. const QAbstractItemModel &m = *reinterpret_cast<const QAbstractItemModel *>(d.data);
  1024. const int rowCount = m.rowCount();
  1025. if (rowCount < 0)
  1026. return;
  1027. const int columnCount = m.columnCount();
  1028. if (columnCount < 0)
  1029. return;
  1030. d.putItem("type", NS "QAbstractItemModel");
  1031. d.beginItem("value");
  1032. d.put("(").put(rowCount).put(",").put(columnCount).put(")");
  1033. d.endItem();
  1034. d.putItem("numchild", "1");
  1035. if (d.dumpChildren) {
  1036. d.beginChildren();
  1037. d.beginHash();
  1038. d.putItem("numchild", "1");
  1039. d.putItem("name", NS "QObject");
  1040. d.putItem("addr", d.data);
  1041. d.putItem("value", m.objectName());
  1042. d.putItem("valueencoded", "2");
  1043. d.putItem("type", NS "QObject");
  1044. d.putItem("displayedtype", m.metaObject()->className());
  1045. d.endHash();
  1046. for (int row = 0; row < rowCount; ++row) {
  1047. for (int column = 0; column < columnCount; ++column) {
  1048. QModelIndex mi = m.index(row, column);
  1049. d.beginHash();
  1050. d.beginItem("name");
  1051. d.put("[").put(row).put(",").put(column).put("]");
  1052. d.endItem();
  1053. d.putItem("value", m.data(mi, Qt::DisplayRole).toString());
  1054. d.putItem("valueencoded", "2");
  1055. //d.putItem("numchild", (m.hasChildren(mi) ? "1" : "0"));
  1056. d.putItem("numchild", m.rowCount(mi) * m.columnCount(mi));
  1057. d.beginItem("addr");
  1058. d.put("$").put(mi.row()).put(",").put(mi.column()).put(",");
  1059. d.put(mi.internalPointer()).put(",").put(mi.model());
  1060. d.endItem();
  1061. d.putItem("type", NS "QAbstractItem");
  1062. d.endHash();
  1063. }
  1064. }
  1065. d.endChildren();
  1066. }
  1067. d.disarm();
  1068. }
  1069. #endif // QT_BOOTSTRAPPED
  1070. static void qDumpQByteArray(QDumper &d)
  1071. {
  1072. qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
  1073. const QByteArray &ba = *reinterpret_cast<const QByteArray *>(d.data);
  1074. const int size = ba.size();
  1075. if (size < 0)
  1076. return;
  1077. if (!ba.isEmpty()) {
  1078. qCheckAccess(ba.constData());
  1079. qCheckAccess(ba.constData() + size);
  1080. }
  1081. d.beginItem("value");
  1082. if (size <= 100)
  1083. d.put(ba);
  1084. else
  1085. d.put(ba.left(100)).put(" <size: ").put(size).put(", cut...>");
  1086. d.endItem();
  1087. d.putItem("valueencoded", "1");
  1088. d.putItem("type", NS "QByteArray");
  1089. d.putItem("numchild", size);
  1090. if (d.dumpChildren) {
  1091. d.putItem("childtype", "char");
  1092. d.putItem("childnumchild", "0");
  1093. d.beginChildren();
  1094. char buf[20];
  1095. for (int i = 0; i != size; ++i) {
  1096. unsigned char c = ba.at(i);
  1097. unsigned char u = (isprint(c) && c != '\'' && c != '"') ? c : '?';
  1098. sprintf(buf, "%02x (%u '%c')", c, c, u);
  1099. d.beginHash();
  1100. d.putItem("value", buf);
  1101. d.endHash();
  1102. }
  1103. d.endChildren();
  1104. }
  1105. d.disarm();
  1106. }
  1107. static void qDumpQChar(QDumper &d)
  1108. {
  1109. qDumpInnerQCharValue(d, *reinterpret_cast<const QChar *>(d.data), "value");
  1110. d.disarm();
  1111. }
  1112. static void qDumpQDate(QDumper &d)
  1113. {
  1114. #ifdef QT_NO_DATESTRING
  1115. qDumpUnknown(d);
  1116. #else
  1117. const QDate &date = *reinterpret_cast<const QDate *>(d.data);
  1118. if (date.isNull()) {
  1119. d.putItem("value", "(null)");
  1120. d.putItem("type", NS "QDate");
  1121. d.putItem("numchild", "0");
  1122. return;
  1123. }
  1124. d.putItem("value", date.toString());
  1125. d.putItem("valueencoded", "2");
  1126. d.putItem("type", NS "QDate");
  1127. d.putItem("numchild", "1");
  1128. if (d.dumpChildren) {
  1129. d.beginChildren();
  1130. d.putHash("isNull", date.isNull());
  1131. d.putHash("toString", date.toString());
  1132. # if QT_VERSION >= 0x040500
  1133. d.putHash("toString_(ISO)", date.toString(Qt::ISODate));
  1134. d.putHash("toString_(SystemLocale)", date.toString(Qt::SystemLocaleDate));
  1135. d.putHash("toString_(Locale)", date.toString(Qt::LocaleDate));
  1136. # endif
  1137. d.endChildren();
  1138. }
  1139. d.disarm();
  1140. #endif // ifdef QT_NO_DATESTRING
  1141. }
  1142. static void qDumpQTime(QDumper &d)
  1143. {
  1144. #ifdef QT_NO_DATESTRING
  1145. qDumpUnknown(d);
  1146. #else
  1147. const QTime &date = *reinterpret_cast<const QTime *>(d.data);
  1148. if (date.isNull()) {
  1149. d.putItem("value", "(null)");
  1150. d.putItem("type", NS "QTime");
  1151. d.putItem("numchild", "0");
  1152. return;
  1153. }
  1154. d.putItem("value", date.toString());
  1155. d.putItem("valueencoded", "2");
  1156. d.putItem("type", NS "QTime");
  1157. d.putItem("numchild", "1");
  1158. if (d.dumpChildren) {
  1159. d.beginChildren();
  1160. d.putHash("isNull", date.isNull());
  1161. d.putHash("toString", date.toString());
  1162. # if QT_VERSION >= 0x040500
  1163. d.putHash("toString_(ISO)", date.toString(Qt::ISODate));
  1164. d.putHash("toString_(SystemLocale)", date.toString(Qt::SystemLocaleDate));
  1165. d.putHash("toString_(Locale)", date.toString(Qt::LocaleDate));
  1166. # endif
  1167. d.endChildren();
  1168. }
  1169. d.disarm();
  1170. #endif // ifdef QT_NO_DATESTRING
  1171. }
  1172. static void qDumpQDateTime(QDumper &d)
  1173. {
  1174. #ifdef QT_NO_DATESTRING
  1175. qDumpUnknown(d);
  1176. #else
  1177. const QDateTime &date = *reinterpret_cast<const QDateTime *>(d.data);
  1178. if (date.isNull()) {
  1179. d.putItem("value", "(null)");
  1180. d.putItem("type", NS "QDateTime");
  1181. d.putItem("numchild", "0");
  1182. d.disarm();
  1183. return;
  1184. }
  1185. d.putItem("value", date.toString());
  1186. d.putItem("valueencoded", "2");
  1187. d.putItem("type", NS "QDateTime");
  1188. d.putItem("numchild", "1");
  1189. if (d.dumpChildren) {
  1190. d.beginChildren();
  1191. d.putHash("toTime_t", (long)date.toTime_t());
  1192. d.putHash("toString", date.toString());
  1193. # if QT_VERSION >= 0x040500
  1194. d.putHash("toString_(ISO)", date.toString(Qt::ISODate));
  1195. d.putHash("toString_(SystemLocale)", date.toString(Qt::SystemLocaleDate));
  1196. d.putHash("toString_(Locale)", date.toString(Qt::LocaleDate));
  1197. # endif
  1198. # if 0
  1199. d.beginHash();
  1200. d.putItem("name", "toUTC");
  1201. d.putItem("exp", "((" NSX "QDateTime" NSY "*)").put(d.data).put(")"
  1202. "->toTimeSpec('" NS "Qt::UTC')");
  1203. d.putItem("type", NS "QDateTime");
  1204. d.putItem("numchild", "1");
  1205. d.endHash();
  1206. # endif
  1207. # if 0
  1208. d.beginHash();
  1209. d.putItem("name", "toLocalTime");
  1210. d.putItem("exp", "((" NSX "QDateTime" NSY "*)").put(d.data).put(")"
  1211. "->toTimeSpec('" NS "Qt::LocalTime')");
  1212. d.putItem("type", NS "QDateTime");
  1213. d.putItem("numchild", "1");
  1214. d.endHash();
  1215. # endif
  1216. d.endChildren();
  1217. }
  1218. d.disarm();
  1219. #endif // ifdef QT_NO_DATESTRING
  1220. }
  1221. static void qDumpQDir(QDumper &d)
  1222. {
  1223. const QDir &dir = *reinterpret_cast<const QDir *>(d.data);
  1224. d.putItem("value", dir.path());
  1225. d.putItem("valueencoded", "2");
  1226. d.putItem("type", NS "QDir");
  1227. d.putItem("numchild", "3");
  1228. if (d.dumpChildren) {
  1229. d.beginChildren();
  1230. d.putHash("absolutePath", dir.absolutePath());
  1231. d.putHash("canonicalPath", dir.canonicalPath());
  1232. d.endChildren();
  1233. }
  1234. d.disarm();
  1235. }
  1236. static void qDumpQFile(QDumper &d)
  1237. {
  1238. const QFile &file = *reinterpret_cast<const QFile *>(d.data);
  1239. d.putItem("value", file.fileName());
  1240. d.putItem("valueencoded", "2");
  1241. d.putItem("type", NS "QFile");
  1242. d.putItem("numchild", "2");
  1243. if (d.dumpChildren) {
  1244. d.beginChildren();
  1245. d.putHash("fileName", file.fileName());
  1246. d.putHash("exists", file.exists());
  1247. d.endChildren();
  1248. }
  1249. d.disarm();
  1250. }
  1251. static void qDumpQFileInfo(QDumper &d)
  1252. {
  1253. const QFileInfo &info = *reinterpret_cast<const QFileInfo *>(d.data);
  1254. d.putItem("value", info.filePath());
  1255. d.putItem("valueencoded", "2");
  1256. d.putItem("type", NS "QFileInfo");
  1257. d.putItem("numchild", "3");
  1258. if (d.dumpChildren) {
  1259. d.beginChildren();
  1260. d.putHash("absolutePath", info.absolutePath());
  1261. d.putHash("absoluteFilePath", info.absoluteFilePath());
  1262. d.putHash("canonicalPath", info.canonicalPath());
  1263. d.putHash("canonicalFilePath", info.canonicalFilePath());
  1264. d.putHash("completeBaseName", info.completeBaseName());
  1265. d.putHash("completeSuffix", info.completeSuffix());
  1266. d.putHash("baseName", info.baseName());
  1267. #ifdef Q_OS_MACX
  1268. d.putHash("isBundle", info.isBundle());
  1269. d.putHash("bundleName", info.bundleName());
  1270. #endif
  1271. d.putHash("fileName", info.fileName());
  1272. d.putHash("filePath", info.filePath());
  1273. d.putHash("group", info.group());
  1274. d.putHash("owner", info.owner());
  1275. d.putHash("path", info.path());
  1276. d.putHash("groupid", (long)info.groupId());
  1277. d.putHash("ownerid", (long)info.ownerId());
  1278. //QFile::Permissions permissions () const
  1279. long perms = info.permissions();
  1280. d.beginHash();
  1281. d.putItem("name", "permissions");
  1282. d.putItem("value", " ");
  1283. d.putItem("type", NS "QFile::Permissions");
  1284. d.putItem("numchild", 10);
  1285. d.beginChildren();
  1286. d.putHash("ReadOwner", bool(perms & QFile::ReadOwner));
  1287. d.putHash("WriteOwner", bool(perms & QFile::WriteOwner));
  1288. d.putHash("ExeOwner", bool(perms & QFile::ExeOwner));
  1289. d.putHash("ReadUser", bool(perms & QFile::ReadUser));
  1290. d.putHash("WriteUser", bool(perms & QFile::WriteUser));
  1291. d.putHash("ExeUser", bool(perms & QFile::ExeUser));
  1292. d.putHash("ReadGroup", bool(perms & QFile::ReadGroup));
  1293. d.putHash("WriteGroup", bool(perms & QFile::WriteGroup));
  1294. d.putHash("ExeGroup", bool(perms & QFile::ExeGroup));
  1295. d.putHash("ReadOther", bool(perms & QFile::ReadOther));
  1296. d.putHash("WriteOther", bool(perms & QFile::WriteOther));
  1297. d.putHash("ExeOther", bool(perms & QFile::ExeOther));
  1298. d.endChildren();
  1299. d.endHash();
  1300. //QDir absoluteDir () const
  1301. //QDir dir () const
  1302. d.putHash("caching", info.caching());
  1303. d.putHash("exists", info.exists());
  1304. d.putHash("isAbsolute", info.isAbsolute());
  1305. d.putHash("isDir", info.isDir());
  1306. d.putHash("isExecutable", info.isExecutable());
  1307. d.putHash("isFile", info.isFile());
  1308. d.putHash("isHidden", info.isHidden());
  1309. d.putHash("isReadable", info.isReadable());
  1310. d.putHash("isRelative", info.isRelative());
  1311. d.putHash("isRoot", info.isRoot());
  1312. d.putHash("isSymLink", info.isSymLink());
  1313. d.putHash("isWritable", info.isWritable());
  1314. d.beginHash();
  1315. d.putItem("name", "created");
  1316. d.putItem("value", info.created().toString());
  1317. d.putItem("valueencoded", "2");
  1318. d.beginItem("exp");
  1319. d.put("((" NSX "QFileInfo" NSY "*)").put(d.data).put(")->created()");
  1320. d.endItem();
  1321. d.putItem("type", NS "QDateTime");
  1322. d.putItem("numchild", "1");
  1323. d.endHash();
  1324. d.beginHash();
  1325. d.putItem("name", "lastModified");
  1326. d.putItem("value", info.lastModified().toString());
  1327. d.putItem("valueencoded", "2");
  1328. d.beginItem("exp");
  1329. d.put("((" NSX "QFileInfo" NSY "*)").put(d.data).put(")->lastModified()");
  1330. d.endItem();
  1331. d.putItem("type", NS "QDateTime");
  1332. d.putItem("numchild", "1");
  1333. d.endHash();
  1334. d.beginHash();
  1335. d.putItem("name", "lastRead");
  1336. d.putItem("value", info.lastRead().toString());
  1337. d.putItem("valueencoded", "2");
  1338. d.beginItem("exp");
  1339. d.put("((" NSX "QFileInfo" NSY "*)").put(d.data).put(")->lastRead()");
  1340. d.endItem();
  1341. d.putItem("type", NS "QDateTime");
  1342. d.putItem("numchild", "1");
  1343. d.endHash();
  1344. d.endChildren();
  1345. }
  1346. d.disarm();
  1347. }
  1348. bool isOptimizedIntKey(const char *keyType)
  1349. {
  1350. return isEqual(keyType, "int")
  1351. #if defined(Q_BYTE_ORDER) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
  1352. || isEqual(keyType, "short")
  1353. || isEqual(keyType, "ushort")
  1354. #endif
  1355. || isEqual(keyType, "uint");
  1356. }
  1357. int hashOffset(bool optimizedIntKey, bool forKey, unsigned keySize, unsigned valueSize)
  1358. {
  1359. // int-key optimization, small value
  1360. struct NodeOS { void *next; uint k; uint v; } nodeOS;
  1361. // int-key optimiatzion, large value
  1362. struct NodeOL { void *next; uint k; void *v; } nodeOL;
  1363. // no optimization, small value
  1364. struct NodeNS { void *next; uint h; uint k; uint v; } nodeNS;
  1365. // no optimization, large value
  1366. struct NodeNL { void *next; uint h; uint k; void *v; } nodeNL;
  1367. // complex key
  1368. struct NodeL { void *next; uint h; void *k; void *v; } nodeL;
  1369. if (forKey) {
  1370. // offsetof(...,...) not yet in Standard C++
  1371. const ulong nodeOSk ( (char *)&nodeOS.k - (char *)&nodeOS );
  1372. const ulong nodeOLk ( (char *)&nodeOL.k - (char *)&nodeOL );
  1373. const ulong nodeNSk ( (char *)&nodeNS.k - (char *)&nodeNS );
  1374. const ulong nodeNLk ( (char *)&nodeNL.k - (char *)&nodeNL );
  1375. const ulong nodeLk ( (char *)&nodeL.k - (char *)&nodeL );
  1376. if (optimizedIntKey)
  1377. return valueSize > sizeof(int) ? nodeOLk : nodeOSk;
  1378. if (keySize > sizeof(int))
  1379. return nodeLk;
  1380. return valueSize > sizeof(int) ? nodeNLk : nodeNSk;
  1381. } else {
  1382. const ulong nodeOSv ( (char *)&nodeOS.v - (char *)&nodeOS );
  1383. const ulong nodeOLv ( (char *)&nodeOL.v - (char *)&nodeOL );
  1384. const ulong nodeNSv ( (char *)&nodeNS.v - (char *)&nodeNS );
  1385. const ulong nodeNLv ( (char *)&nodeNL.v - (char *)&nodeNL );
  1386. const ulong nodeLv ( (char *)&nodeL.v - (char *)&nodeL );
  1387. if (optimizedIntKey)
  1388. return valueSize > sizeof(int) ? nodeOLv : nodeOSv;
  1389. if (keySize > sizeof(int))
  1390. return nodeLv;
  1391. return valueSize > sizeof(int) ? nodeNLv : nodeNSv;
  1392. }
  1393. }
  1394. static void qDumpQHash(QDumper &d)
  1395. {
  1396. qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
  1397. const char *keyType = d.templateParameters[0];
  1398. const char *valueType = d.templateParameters[1];
  1399. QHashData *h = *reinterpret_cast<QHashData *const*>(d.data);
  1400. qCheckPointer(h->fakeNext);
  1401. qCheckPointer(h->buckets);
  1402. unsigned keySize = d.extraInt[0];
  1403. unsigned valueSize = d.extraInt[1];
  1404. int n = h->size;
  1405. if (n < 0)
  1406. return;
  1407. if (n > 0) {
  1408. qCheckPointer(h->fakeNext);
  1409. qCheckPointer(*h->buckets);
  1410. }
  1411. d.putItemCount("value", n);
  1412. d.putItem("numchild", n);
  1413. if (d.dumpChildren) {
  1414. const bool isSimpleKey = isSimpleType(keyType);
  1415. const bool isSimpleValue = isSimpleType(valueType);
  1416. const bool opt = isOptimizedIntKey(keyType);
  1417. const int keyOffset = hashOffset(opt, true, keySize, valueSize);
  1418. const int valueOffset = hashOffset(opt, false, keySize, valueSize);
  1419. #if 0
  1420. d.beginItem("extra");
  1421. d.put("isSimpleKey: ").put(isSimpleKey);
  1422. d.put(" isSimpleValue: ").put(isSimpleValue);
  1423. d.put(" valueType: '").put(isSimpleValue);
  1424. d.put(" keySize: ").put(keyOffset);
  1425. d.put(" valueOffset: ").put(valueOffset);
  1426. d.put(" opt: ").put(opt);
  1427. d.endItem();
  1428. #endif
  1429. QHashData::Node *node = h->firstNode();
  1430. QHashData::Node *end = reinterpret_cast<QHashData::Node *>(h);
  1431. int i = 0;
  1432. d.beginChildren();
  1433. while (node != end) {
  1434. d.beginHash();
  1435. qDumpInnerValueHelper(d, keyType, addOffset(node, keyOffset), "key");
  1436. qDumpInnerValueHelper(d, valueType, addOffset(node, valueOffset));
  1437. if (isSimpleKey && isSimpleValue) {
  1438. d.putItem("type", valueType);
  1439. d.putItem("addr", addOffset(node, valueOffset));
  1440. } else {
  1441. d.putItem("addr", node);
  1442. d.beginItem("type");
  1443. d.put(NS "QHashNode<").put(keyType).put(",")
  1444. .put(valueType).put(" >");
  1445. d.endItem();
  1446. }
  1447. d.endHash();
  1448. ++i;
  1449. node = QHashData::nextNode(node);
  1450. }
  1451. d.endChildren();
  1452. }
  1453. d.disarm();
  1454. }
  1455. static void qDumpQHashNode(QDumper &d)
  1456. {
  1457. const QHashData *h = reinterpret_cast<const QHashData *>(d.data);
  1458. const char *keyType = d.templateParameters[0];
  1459. const char *valueType = d.templateParameters[1];
  1460. unsigned keySize = d.extraInt[0];
  1461. unsigned valueSize = d.extraInt[1];
  1462. bool opt = isOptimizedIntKey(keyType);
  1463. int keyOffset = hashOffset(opt, true, keySize, valueSize);
  1464. int valueOffset = hashOffset(opt, false, keySize, valueSize);
  1465. if (isSimpleType(valueType))
  1466. qDumpInnerValueHelper(d, valueType, addOffset(h, valueOffset));
  1467. else
  1468. d.putItem("value", "");
  1469. d.putItem("numchild", 2);
  1470. if (d.dumpChildren) {
  1471. // there is a hash specialization in case the keys are integers or shorts
  1472. d.beginChildren();
  1473. d.beginHash();
  1474. d.putItem("name", "key");
  1475. d.putItem("type", keyType);
  1476. d.putItem("addr", addOffset(h, keyOffset));
  1477. d.endHash();
  1478. d.beginHash();
  1479. d.putItem("name", "value");
  1480. d.putItem("type", valueType);

Large files files are truncated, but you can click here to view the full file