PageRenderTime 63ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/share/qtcreator/dumper/dumper.cpp

https://bitbucket.org/kyanha/qt-creator
C++ | 3809 lines | 3347 code | 262 blank | 200 comment | 479 complexity | 22a4a2eb928155cb6332f220bac7630e MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1

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

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

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