qttypes.py 94.3 KB
Newer Older
hjk's avatar
hjk committed
1
############################################################################
hjk's avatar
hjk committed
2
#
Eike Ziller's avatar
Eike Ziller committed
3 4
# Copyright (C) 2015 The Qt Company Ltd.
# Contact: http://www.qt.io/licensing
hjk's avatar
hjk committed
5
#
hjk's avatar
hjk committed
6 7 8 9 10 11
# This file is part of Qt Creator.
#
# Commercial License Usage
# Licensees holding valid commercial Qt licenses may use this file in
# accordance with the commercial license agreement provided with the
# Software or, alternatively, in accordance with the terms contained in
Eike Ziller's avatar
Eike Ziller committed
12 13
# a written agreement between you and The Qt Company.  For licensing terms and
# conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
# use the contact form at http://www.qt.io/contact-us.
hjk's avatar
hjk committed
15 16 17
#
# GNU Lesser General Public License Usage
# Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18 19 20 21 22 23
# General Public License version 2.1 or version 3 as published by the Free
# Software Foundation and appearing in the file LICENSE.LGPLv21 and
# LICENSE.LGPLv3 included in the packaging of this file.  Please review the
# following information to ensure the GNU Lesser General Public License
# requirements will be met: https://www.gnu.org/licenses/lgpl.html and
# http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
hjk's avatar
hjk committed
24
#
Eike Ziller's avatar
Eike Ziller committed
25 26
# In addition, as a special exception, The Qt Company gives you certain additional
# rights.  These rights are described in The Qt Company LGPL Exception
hjk's avatar
hjk committed
27 28 29
# version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
#
#############################################################################
hjk's avatar
hjk committed
30

31
import platform
32
from dumper import *
hjk's avatar
hjk committed
33 34 35


def qdump__QAtomicInt(d, value):
hjk's avatar
hjk committed
36
    d.putValue(int(value["_q_value"]))
hjk's avatar
hjk committed
37 38 39 40
    d.putNumChild(0)


def qdump__QBasicAtomicInt(d, value):
hjk's avatar
hjk committed
41
    d.putValue(int(value["_q_value"]))
hjk's avatar
hjk committed
42 43 44
    d.putNumChild(0)


hjk's avatar
hjk committed
45
def qdump__QAtomicPointer(d, value):
hjk's avatar
hjk committed
46
    d.putType(value.type)
hjk's avatar
hjk committed
47
    q = value["_q_value"]
48
    p = toInteger(q)
hjk's avatar
hjk committed
49 50
    d.putValue("@0x%x" % p)
    d.putNumChild(1 if p else 0)
hjk's avatar
hjk committed
51 52
    if d.isExpanded():
        with Children(d):
hjk's avatar
hjk committed
53
           d.putSubItem("_q_value", q.dereference())
hjk's avatar
hjk committed
54

55
def qform__QByteArray():
56 57
    return [Latin1StringFormat, SeparateLatin1StringFormat,
            Utf8StringFormat, SeparateUtf8StringFormat ]
58

hjk's avatar
hjk committed
59
def qdump__QByteArray(d, value):
hjk's avatar
hjk committed
60
    data, size, alloc = d.byteArrayData(value)
61
    d.check(alloc == 0 or (0 <= size and size <= alloc and alloc <= 100000000))
62
    d.putNumChild(size)
63
    elided, p = d.encodeByteArrayHelper(d.extractPointer(value), d.displayStringLimit)
64 65
    displayFormat = d.currentItemFormat()
    if displayFormat == AutomaticFormat or displayFormat == Latin1StringFormat:
66
        d.putValue(p, Hex2EncodedLatin1, elided=elided)
67
    elif displayFormat == SeparateLatin1StringFormat:
68
        d.putValue(p, Hex2EncodedLatin1, elided=elided)
69
        d.putField("editformat", DisplayLatin1String)
70
        d.putField("editvalue", d.encodeByteArray(value, limit=100000))
71
    elif displayFormat == Utf8StringFormat:
72
        d.putValue(p, Hex2EncodedUtf8, elided=elided)
73
    elif displayFormat == SeparateUtf8StringFormat:
74
        d.putValue(p, Hex2EncodedUtf8, elided=elided)
75
        d.putField("editformat", DisplayUtf8String)
76
        d.putField("editvalue", d.encodeByteArray(value, limit=100000))
hjk's avatar
hjk committed
77
    if d.isExpanded():
78
        d.putArrayData(data, size, d.charType())
hjk's avatar
hjk committed
79

hjk's avatar
hjk committed
80 81
def qdump__QByteArrayData(d, value):
    data, size, alloc = d.byteArrayDataHelper(d.addressOf(value))
82
    d.check(alloc == 0 or (0 <= size and size <= alloc and alloc <= 100000000))
hjk's avatar
hjk committed
83 84 85 86 87 88
    d.putValue(d.readMemory(data, size), Hex2EncodedLatin1)
    d.putNumChild(1)
    if d.isExpanded():
        with Children(d):
            d.putIntItem("size", size)
            d.putIntItem("alloc", alloc)
hjk's avatar
hjk committed
89

hjk's avatar
hjk committed
90
def qdump__QChar(d, value):
hjk's avatar
hjk committed
91
    d.putValue(int(value["ucs"]))
hjk's avatar
hjk committed
92 93 94
    d.putNumChild(0)


hjk's avatar
hjk committed
95
def qform__QAbstractItemModel():
96
    return [SimpleFormat, EnhancedFormat]
97

hjk's avatar
hjk committed
98
def qdump__QAbstractItemModel(d, value):
99 100
    displayFormat = d.currentItemFormat()
    if displayFormat == SimpleFormat:
101 102
        d.putPlainChildren(value)
        return
103
    #displayFormat == EnhancedFormat:
104
    # Create a default-constructed QModelIndex on the stack.
105
    try:
106
        ri = d.makeValue(d.qtNamespace() + "QModelIndex", "-1, -1, 0, 0")
hjk's avatar
hjk committed
107 108
        this_ = d.makeExpression(value)
        ri_ = d.makeExpression(ri)
109 110
        rowCount = int(d.parseAndEvaluate("%s.rowCount(%s)" % (this_, ri_)))
        columnCount = int(d.parseAndEvaluate("%s.columnCount(%s)" % (this_, ri_)))
111
    except:
hjk's avatar
hjk committed
112
        d.putPlainChildren(value)
113
        return
114 115
    d.putValue("%d x %d" % (rowCount, columnCount))
    d.putNumChild(rowCount * columnCount)
hjk's avatar
hjk committed
116 117
    if d.isExpanded():
        with Children(d, numChild=rowCount * columnCount, childType=ri.type):
118 119 120
            i = 0
            for row in xrange(rowCount):
                for column in xrange(columnCount):
hjk's avatar
hjk committed
121
                    with SubItem(d, i):
122
                        d.putName("[%s, %s]" % (row, column))
123
                        mi = d.parseAndEvaluate("%s.index(%d,%d,%s)"
124 125 126 127
                            % (this_, row, column, ri_))
                        #warn("MI: %s " % mi)
                        #name = "[%d,%d]" % (row, column)
                        #d.putValue("%s" % mi)
hjk's avatar
hjk committed
128
                        d.putItem(mi)
129 130 131 132 133 134 135 136
                        i = i + 1
                        #warn("MI: %s " % mi)
                        #d.putName("[%d,%d]" % (row, column))
                        #d.putValue("%s" % mi)
                        #d.putNumChild(0)
                        #d.putType(mi.type)
    #gdb.execute("call free($ri)")

137
def qform__QModelIndex():
138
    return [SimpleFormat, EnhancedFormat]
139

hjk's avatar
hjk committed
140
def qdump__QModelIndex(d, value):
141 142
    displayFormat = d.currentItemFormat()
    if displayFormat == SimpleFormat:
143 144
        d.putPlainChildren(value)
        return
hjk's avatar
hjk committed
145 146
    r = value["r"]
    c = value["c"]
147 148 149 150
    try:
        p = value["p"]
    except:
        p = value["i"]
hjk's avatar
hjk committed
151
    m = value["m"]
152
    if d.isNull(m) or r < 0 or c < 0:
153 154 155 156
        d.putValue("(invalid)")
        d.putPlainChildren(value)
        return

157 158
    mm = m.dereference()
    mm = mm.cast(mm.type.unqualified())
159
    ns = d.qtNamespace()
160
    try:
161
        mi = d.makeValue(ns + "QModelIndex", "%s,%s,%s,%s" % (r, c, p, m))
hjk's avatar
hjk committed
162 163
        mm_ = d.makeExpression(mm)
        mi_ = d.makeExpression(mi)
164 165
        rowCount = int(d.parseAndEvaluate("%s.rowCount(%s)" % (mm_, mi_)))
        columnCount = int(d.parseAndEvaluate("%s.columnCount(%s)" % (mm_, mi_)))
166
    except:
hjk's avatar
hjk committed
167
        d.putPlainChildren(value)
168
        return
169 170 171

    try:
        # Access DisplayRole as value
172
        val = d.parseAndEvaluate("%s.data(%s, 0)" % (mm_, mi_))
hjk's avatar
hjk committed
173
        v = val["d"]["data"]["ptr"]
174
        d.putStringValue(d.makeValue(ns + 'QString', v))
175
    except:
hjk's avatar
hjk committed
176
        d.putValue("")
177

178
    d.putNumChild(1)
179 180
    if d.isExpanded():
        with Children(d):
181
            d.putFields(value, False)
182 183 184 185 186
            i = 0
            for row in xrange(rowCount):
                for column in xrange(columnCount):
                    with UnnamedSubItem(d, i):
                        d.putName("[%s, %s]" % (row, column))
187
                        mi2 = d.parseAndEvaluate("%s.index(%d,%d,%s)"
188 189 190
                            % (mm_, row, column, mi_))
                        d.putItem(mi2)
                        i = i + 1
191
            d.putCallItem("parent", value, "parent")
192 193
    #gdb.execute("call free($mi)")

hjk's avatar
hjk committed
194

hjk's avatar
hjk committed
195
def qdump__QDate(d, value):
196
    jd = int(value["jd"])
197
    if jd:
198 199 200 201 202
        d.putValue(jd, JulianDate)
        d.putNumChild(1)
        if d.isExpanded():
            # FIXME: This improperly uses complex return values.
            with Children(d):
203 204 205 206 207 208 209 210 211
                if d.canCallLocale():
                    d.putCallItem("toString", value, "toString",
                        d.enumExpression("DateFormat", "TextDate"))
                    d.putCallItem("(ISO)", value, "toString",
                        d.enumExpression("DateFormat", "ISODate"))
                    d.putCallItem("(SystemLocale)", value, "toString",
                        d.enumExpression("DateFormat", "SystemLocaleDate"))
                    d.putCallItem("(Locale)", value, "toString",
                        d.enumExpression("DateFormat", "LocaleDate"))
212
                d.putFields(value)
213 214 215
    else:
        d.putValue("(invalid)")
        d.putNumChild(0)
hjk's avatar
hjk committed
216 217


hjk's avatar
hjk committed
218
def qdump__QTime(d, value):
hjk's avatar
hjk committed
219 220 221
    mds = int(value["mds"])
    if mds >= 0:
        d.putValue(mds, MillisecondsSinceMidnight)
222 223 224 225
        d.putNumChild(1)
        if d.isExpanded():
            # FIXME: This improperly uses complex return values.
            with Children(d):
226 227 228 229
                d.putCallItem("toString", value, "toString",
                    d.enumExpression("DateFormat", "TextDate"))
                d.putCallItem("(ISO)", value, "toString",
                    d.enumExpression("DateFormat", "ISODate"))
230 231 232 233 234
                if d.canCallLocale():
                    d.putCallItem("(SystemLocale)", value, "toString",
                        d.enumExpression("DateFormat", "SystemLocaleDate"))
                    d.putCallItem("(Locale)", value, "toString",
                        d.enumExpression("DateFormat", "LocaleDate"))
235
                d.putFields(value)
236 237 238
    else:
        d.putValue("(invalid)")
        d.putNumChild(0)
239 240


hjk's avatar
hjk committed
241
def qdump__QTimeZone(d, value):
242
    base = d.extractPointer(value)
243
    if base == 0:
hjk's avatar
hjk committed
244 245 246 247
        d.putValue("(null)")
        d.putNumChild(0)
        return
    idAddr = base + 2 * d.ptrSize() # [QSharedData] + [vptr]
hjk's avatar
hjk committed
248
    d.putByteArrayValue(idAddr)
hjk's avatar
hjk committed
249 250 251
    d.putPlainChildren(value["d"])


hjk's avatar
hjk committed
252
def qdump__QDateTime(d, value):
253 254 255 256
    qtVersion = d.qtVersion()
    isValid = False
    # This relies on the Qt4/Qt5 internal structure layout:
    # {sharedref(4), ...
257
    base = d.extractPointer(value)
258
    is32bit = d.is32bit()
259
    if qtVersion >= 0x050200:
260
        if d.isWindowsTarget():
261 262 263 264 265 266 267 268 269 270 271 272
            msecsOffset = 8
            specOffset = 16
            offsetFromUtcOffset = 20
            timeZoneOffset = 24
            statusOffset = 28 if is32bit else 32
        else:
            msecsOffset = 4 if is32bit else 8
            specOffset = 12 if is32bit else 16
            offsetFromUtcOffset = 16 if is32bit else 20
            timeZoneOffset = 20 if is32bit else 24
            statusOffset = 24 if is32bit else 32
        status = d.extractInt(base + statusOffset)
273
        if int(status & 0x0c == 0x0c): # ValidDate and ValidTime
274
            isValid = True
275 276 277 278
            msecs = d.extractInt64(base + msecsOffset)
            spec = d.extractInt(base + specOffset)
            offset = d.extractInt(base + offsetFromUtcOffset)
            tzp = d.extractPointer(base + timeZoneOffset)
279 280 281 282
            if tzp == 0:
                tz = ""
            else:
                idBase = tzp + 2 * d.ptrSize() # [QSharedData] + [vptr]
283
                elided, tz = d.encodeByteArrayHelper(d.extractPointer(idBase), limit=100)
284 285
            d.putValue("%s/%s/%s/%s/%s" % (msecs, spec, offset, tz, status),
                DateTimeInternal)
286 287 288 289 290 291
    else:
        # This relies on the Qt4/Qt5 internal structure layout:
        # {sharedref(4), date(8), time(4+x)}
        # QDateTimePrivate:
        # - QAtomicInt ref;    (padded on 64 bit)
        # -     [QDate date;]
292
        # -      -  uint jd in Qt 4,  qint64 in Qt 5.0 and Qt 5.1; padded on 64 bit
293 294 295
        # -     [QTime time;]
        # -      -  uint mds;
        # -  Spec spec;
296 297 298 299
        dateSize = 8 if qtVersion >= 0x050000 else 4 # Qt5: qint64, Qt4 uint
        # 4 byte padding after 4 byte QAtomicInt if we are on 64 bit and QDate is 64 bit
        refPlusPadding = 8 if qtVersion >= 0x050000 and not d.is32bit() else 4
        dateBase = base + refPlusPadding
300 301 302 303 304 305 306
        timeBase = dateBase + dateSize
        mds = d.extractInt(timeBase)
        isValid = mds > 0
        if isValid:
            jd = d.extractInt(dateBase)
            d.putValue("%s/%s" % (jd, mds), JulianDateAndMillisecondsSinceMidnight)
    if isValid:
307 308 309 310 311
        d.putNumChild(1)
        if d.isExpanded():
            # FIXME: This improperly uses complex return values.
            with Children(d):
                d.putCallItem("toTime_t", value, "toTime_t")
312 313 314 315 316 317 318 319 320 321 322 323 324
                if d.canCallLocale():
                    d.putCallItem("toString", value, "toString",
                        d.enumExpression("DateFormat", "TextDate"))
                    d.putCallItem("(ISO)", value, "toString",
                        d.enumExpression("DateFormat", "ISODate"))
                    d.putCallItem("toUTC", value, "toTimeSpec",
                        d.enumExpression("TimeSpec", "UTC"))
                    d.putCallItem("(SystemLocale)", value, "toString",
                        d.enumExpression("DateFormat", "SystemLocaleDate"))
                    d.putCallItem("(Locale)", value, "toString",
                        d.enumExpression("DateFormat", "LocaleDate"))
                    d.putCallItem("toLocalTime", value, "toTimeSpec",
                        d.enumExpression("TimeSpec", "LocalTime"))
325
                d.putFields(value)
326 327 328
    else:
        d.putValue("(invalid)")
        d.putNumChild(0)
hjk's avatar
hjk committed
329 330 331


def qdump__QDir(d, value):
hjk's avatar
hjk committed
332
    d.putNumChild(1)
333
    privAddress = d.extractPointer(value)
334 335
    bit32 = d.is32bit()
    qt5 = d.qtVersion() >= 0x050000
336 337 338 339 340 341 342 343 344 345

    # Change 9fc0965 reorders members again.
    #  bool fileListsInitialized;\n"
    #  QStringList files;\n"
    #  QFileInfoList fileInfos;\n"
    #  QStringList nameFilters;\n"
    #  QDir::SortFlags sort;\n"
    #  QDir::Filters filters;\n"

    # Before 9fc0965:
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
    # QDirPrivate:
    # QAtomicInt ref
    # QStringList nameFilters;
    # QDir::SortFlags sort;
    # QDir::Filters filters;
    # // qt3support:
    # QChar filterSepChar;
    # bool matchAllDirs;
    # // end qt3support
    # QScopedPointer<QAbstractFileEngine> fileEngine;
    # bool fileListsInitialized;
    # QStringList files;
    # QFileInfoList fileInfos;
    # QFileSystemEntry dirEntry;
    # QFileSystemEntry absoluteDirEntry;
361

362 363 364 365 366 367 368 369
    # QFileSystemEntry:
    # QString m_filePath
    # QByteArray m_nativeFilePath
    # qint16 m_lastSeparator
    # qint16 m_firstDotInFileName
    # qint16 m_lastDotInFileName
    # + 2 byte padding
    fileSystemEntrySize = 2 * d.ptrSize() + 8
370

371 372 373 374 375
    if d.qtVersion() < 0x050200:
        case = 0
    elif d.qtVersion() >= 0x050300:
        case = 1
    else:
376
        # Try to distinguish bool vs QStringList at the first item
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
        # after the (padded) refcount. If it looks like a bool assume
        # this is after 9fc0965. This is not safe.
        firstValue = d.extractInt(privAddress + d.ptrSize())
        case = 1 if firstValue == 0 or firstValue == 1 else 0

    if case == 1:
        if bit32:
            filesOffset = 4
            fileInfosOffset = 8
            dirEntryOffset = 0x20
            absoluteDirEntryOffset = 0x30
        else:
            filesOffset = 0x08
            fileInfosOffset = 0x10
            dirEntryOffset = 0x30
            absoluteDirEntryOffset = 0x48
    else:
394 395 396 397 398 399 400 401
        # Assume this is before 9fc0965.
        qt3support = d.isQt3Support()
        qt3SupportAddition = d.ptrSize() if qt3support else 0
        filesOffset = (24 if bit32 else 40) + qt3SupportAddition
        fileInfosOffset = filesOffset + d.ptrSize()
        dirEntryOffset = fileInfosOffset + d.ptrSize()
        absoluteDirEntryOffset = dirEntryOffset + fileSystemEntrySize

hjk's avatar
hjk committed
402
    d.putStringValue(privAddress + dirEntryOffset)
hjk's avatar
hjk committed
403 404
    if d.isExpanded():
        with Children(d):
405
            ns = d.qtNamespace()
406
            d.call(value, "count")  # Fill cache.
407 408 409
            #d.putCallItem("absolutePath", value, "absolutePath")
            #d.putCallItem("canonicalPath", value, "canonicalPath")
            with SubItem(d, "absolutePath"):
410
                typ = d.lookupType(ns + "QString")
411
                d.putItem(d.createValue(privAddress + absoluteDirEntryOffset, typ))
412
            with SubItem(d, "entryInfoList"):
413
                typ = d.lookupType(ns + "QList<" + ns + "QFileInfo>")
414
                d.putItem(d.createValue(privAddress + fileInfosOffset, typ))
415
            with SubItem(d, "entryList"):
416
                typ = d.lookupType(ns + "QStringList")
417
                d.putItem(d.createValue(privAddress + filesOffset, typ))
418
            d.putFields(value)
hjk's avatar
hjk committed
419 420


hjk's avatar
hjk committed
421
def qdump__QFile(d, value):
422
    # 9fc0965 and a373ffcd change the layout of the private structure
hjk's avatar
hjk committed
423
    qtVersion = d.qtVersion()
424
    is32bit = d.is32bit()
425 426 427 428 429 430 431 432 433 434 435
    if qtVersion >= 0x050500:
        if d.isWindowsTarget():
            offset = 164 if is32bit else 248
        else:
            offset = 156 if is32bit else 248
    elif qtVersion >= 0x050400:
        if d.isWindowsTarget():
            offset = 188 if is32bit else 272
        else:
            offset = 180 if is32bit else 272
    elif qtVersion > 0x050200:
436 437 438 439
        if d.isWindowsTarget():
            offset = 180 if is32bit else 272
        else:
            offset = 176 if is32bit else 272
hjk's avatar
hjk committed
440
    elif qtVersion >= 0x050000:
441
        offset = 176 if is32bit else 280
hjk's avatar
hjk committed
442
    else:
443 444 445 446
        if d.isWindowsTarget():
            offset = 144 if is32bit else 232
        else:
            offset = 140 if is32bit else 232
447
    privAddress = d.extractPointer(d.addressOf(value) + d.ptrSize())
hjk's avatar
hjk committed
448
    fileNameAddress = privAddress + offset
hjk's avatar
hjk committed
449
    d.putStringValue(fileNameAddress)
hjk's avatar
hjk committed
450
    d.putNumChild(1)
hjk's avatar
hjk committed
451 452
    if d.isExpanded():
        with Children(d):
hjk's avatar
hjk committed
453
            d.putCallItem("exists", value, "exists")
hjk's avatar
hjk committed
454
            d.putFields(value)
hjk's avatar
hjk committed
455 456


hjk's avatar
hjk committed
457
def qdump__QFileInfo(d, value):
458
    privAddress = d.extractPointer(value)
459 460 461 462 463 464 465 466
    #bit32 = d.is32bit()
    #qt5 = d.qtVersion() >= 0x050000
    #try:
    #    d.putStringValue(value["d_ptr"]["d"].dereference()["fileNames"][3])
    #except:
    #    d.putPlainChildren(value)
    #    return
    filePathAddress = privAddress + d.ptrSize()
hjk's avatar
hjk committed
467
    d.putStringValue(filePathAddress)
hjk's avatar
hjk committed
468
    d.putNumChild(1)
hjk's avatar
hjk committed
469
    if d.isExpanded():
470 471
        ns = d.qtNamespace()
        with Children(d, childType=d.lookupType(ns + "QString")):
hjk's avatar
hjk committed
472 473 474 475 476 477 478
            d.putCallItem("absolutePath", value, "absolutePath")
            d.putCallItem("absoluteFilePath", value, "absoluteFilePath")
            d.putCallItem("canonicalPath", value, "canonicalPath")
            d.putCallItem("canonicalFilePath", value, "canonicalFilePath")
            d.putCallItem("completeBaseName", value, "completeBaseName")
            d.putCallItem("completeSuffix", value, "completeSuffix")
            d.putCallItem("baseName", value, "baseName")
479 480
            if False:
                #ifdef Q_OS_MACX
hjk's avatar
hjk committed
481 482 483 484
                d.putCallItem("isBundle", value, "isBundle")
                d.putCallItem("bundleName", value, "bundleName")
            d.putCallItem("fileName", value, "fileName")
            d.putCallItem("filePath", value, "filePath")
485
            # Crashes gdb (archer-tromey-python, at dad6b53fe)
hjk's avatar
hjk committed
486 487 488
            #d.putCallItem("group", value, "group")
            #d.putCallItem("owner", value, "owner")
            d.putCallItem("path", value, "path")
489

hjk's avatar
hjk committed
490 491
            d.putCallItem("groupid", value, "groupId")
            d.putCallItem("ownerid", value, "ownerId")
492 493

            #QFile::Permissions permissions () const
494
            perms = d.call(value, "permissions")
495 496 497
            if perms is None:
                d.putValue("<not available>")
            else:
hjk's avatar
hjk committed
498
                with SubItem(d, "permissions"):
499
                    d.putEmptyValue()
500
                    d.putType(ns + "QFile::Permissions")
501
                    d.putNumChild(10)
hjk's avatar
hjk committed
502
                    if d.isExpanded():
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
                        with Children(d, 10):
                            perms = perms['i']
                            d.putBoolItem("ReadOwner",  perms & 0x4000)
                            d.putBoolItem("WriteOwner", perms & 0x2000)
                            d.putBoolItem("ExeOwner",   perms & 0x1000)
                            d.putBoolItem("ReadUser",   perms & 0x0400)
                            d.putBoolItem("WriteUser",  perms & 0x0200)
                            d.putBoolItem("ExeUser",    perms & 0x0100)
                            d.putBoolItem("ReadGroup",  perms & 0x0040)
                            d.putBoolItem("WriteGroup", perms & 0x0020)
                            d.putBoolItem("ExeGroup",   perms & 0x0010)
                            d.putBoolItem("ReadOther",  perms & 0x0004)
                            d.putBoolItem("WriteOther", perms & 0x0002)
                            d.putBoolItem("ExeOther",   perms & 0x0001)

            #QDir absoluteDir () const
            #QDir dir () const
hjk's avatar
hjk committed
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
            d.putCallItem("caching", value, "caching")
            d.putCallItem("exists", value, "exists")
            d.putCallItem("isAbsolute", value, "isAbsolute")
            d.putCallItem("isDir", value, "isDir")
            d.putCallItem("isExecutable", value, "isExecutable")
            d.putCallItem("isFile", value, "isFile")
            d.putCallItem("isHidden", value, "isHidden")
            d.putCallItem("isReadable", value, "isReadable")
            d.putCallItem("isRelative", value, "isRelative")
            d.putCallItem("isRoot", value, "isRoot")
            d.putCallItem("isSymLink", value, "isSymLink")
            d.putCallItem("isWritable", value, "isWritable")
            d.putCallItem("created", value, "created")
            d.putCallItem("lastModified", value, "lastModified")
            d.putCallItem("lastRead", value, "lastRead")
535
            d.putFields(value)
hjk's avatar
hjk committed
536 537 538 539


def qdump__QFixed(d, value):
    v = int(value["val"])
hjk's avatar
hjk committed
540 541 542 543
    d.putValue("%s/64 = %s" % (v, v/64.0))
    d.putNumChild(0)


544 545 546
def qform__QFiniteStack():
    return arrayForms()

hjk's avatar
hjk committed
547
def qdump__QFiniteStack(d, value):
hjk's avatar
hjk committed
548 549
    alloc = int(value["_alloc"])
    size = int(value["_size"])
550
    d.check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000)
hjk's avatar
hjk committed
551
    d.putItemCount(size)
552
    d.putPlotData(value["_array"], size, d.templateArgument(value.type, 0))
hjk's avatar
hjk committed
553

554

hjk's avatar
hjk committed
555 556
def qdump__QFlags(d, value):
    i = value["i"]
557
    try:
558
        enumType = d.templateArgument(value.type.unqualified(), 0)
559 560 561
        d.putValue("%s (%s)" % (i.cast(enumType), i))
    except:
        d.putValue("%s" % i)
hjk's avatar
hjk committed
562 563 564
    d.putNumChild(0)


565 566 567
def qform__QHash():
    return mapForms()

hjk's avatar
hjk committed
568
def qdump__QHash(d, value):
hjk's avatar
hjk committed
569

hjk's avatar
hjk committed
570 571 572
    def hashDataFirstNode(dPtr, numBuckets):
        ePtr = dPtr.cast(nodeTypePtr)
        bucket = dPtr.dereference()["buckets"]
573
        for n in xrange(numBuckets - 1, -1, -1):
hjk's avatar
hjk committed
574 575 576
            n = n - 1
            if n < 0:
                break
577
            if d.pointerValue(bucket.dereference()) != d.pointerValue(ePtr):
hjk's avatar
hjk committed
578 579
                return bucket.dereference()
            bucket = bucket + 1
hjk's avatar
hjk committed
580
        return ePtr;
hjk's avatar
hjk committed
581

582 583
    def hashDataNextNode(nodePtr, numBuckets):
        nextPtr = nodePtr.dereference()["next"]
584
        if d.pointerValue(nextPtr.dereference()["next"]):
585 586 587 588
            return nextPtr
        start = (int(nodePtr.dereference()["h"]) % numBuckets) + 1
        dPtr = nextPtr.cast(dataTypePtr)
        bucket = dPtr.dereference()["buckets"] + start
589
        for n in xrange(numBuckets - start):
590
            if d.pointerValue(bucket.dereference()) != d.pointerValue(nextPtr):
hjk's avatar
hjk committed
591 592
                return bucket.dereference()
            bucket += 1
593
        return nextPtr
hjk's avatar
hjk committed
594

595 596
    keyType = d.templateArgument(value.type, 0)
    valueType = d.templateArgument(value.type, 1)
hjk's avatar
hjk committed
597

598
    anon = d.childAt(value, 0)
599 600
    d_ptr = anon["d"]
    e_ptr = anon["e"]
hjk's avatar
hjk committed
601
    size = int(d_ptr["size"])
hjk's avatar
hjk committed
602

hjk's avatar
hjk committed
603 604
    dataTypePtr = d_ptr.type    # QHashData *  = { Node *fakeNext, Node *buckets }
    nodeTypePtr = d_ptr.dereference()["fakeNext"].type    # QHashData::Node
hjk's avatar
hjk committed
605

606 607
    d.check(0 <= size and size <= 100 * 1000 * 1000)
    d.checkRef(d_ptr["ref"])
hjk's avatar
hjk committed
608

609
    d.putItemCount(size)
hjk's avatar
hjk committed
610
    if d.isExpanded():
611
        numBuckets = int(d_ptr.dereference()["numBuckets"])
hjk's avatar
hjk committed
612
        innerType = e_ptr.dereference().type
613 614
        isCompact = d.isMapCompact(keyType, valueType)
        childType = valueType if isCompact else innerType
hjk's avatar
hjk committed
615
        with Children(d, size, maxNumChild=1000, childType=childType):
616
            j = 0
617
            for i in d.childRange():
618 619 620 621 622
                if i == 0:
                    node = hashDataFirstNode(d_ptr, numBuckets)
                else:
                    node = hashDataNextNode(node, numBuckets)
                it = node.dereference().cast(innerType)
hjk's avatar
hjk committed
623
                with SubItem(d, i):
624
                    if isCompact:
625
                        key = it["key"]
626
                        d.putMapName(key, j)
627
                        d.putItem(it["value"])
628
                        d.putType(valueType)
629
                        j += 1
630
                    else:
hjk's avatar
hjk committed
631
                        d.putItem(it)
hjk's avatar
hjk committed
632 633


634 635 636
def qform__QHashNode():
    return mapForms()

hjk's avatar
hjk committed
637 638 639
def qdump__QHashNode(d, value):
    key = value["key"]
    val = value["value"]
640 641 642 643 644 645 646 647 648 649 650
    if d.isMapCompact(key.type, val.type):
        d.putMapName(key)
        d.putItem(val)
        d.putType(value.type)
    else:
        d.putEmptyValue()
        d.putNumChild(2)
        if d.isExpanded():
            with Children(d):
                d.putSubItem("key", key)
                d.putSubItem("value", val)
hjk's avatar
hjk committed
651 652


653 654
def qHashIteratorHelper(d, value):
    typeName = str(value.type)
655 656
    hashTypeName = typeName[0:typeName.rfind("::")]
    hashType = d.lookupType(hashTypeName)
657 658
    keyType = d.templateArgument(hashType, 0)
    valueType = d.templateArgument(hashType, 1)
659
    d.putNumChild(1)
660
    d.putEmptyValue()
661 662
    if d.isExpanded():
        with Children(d):
663 664 665 666
            # We need something like QHash<int, float>::iterator
            # -> QHashNode<int, float> with 'proper' spacing,
            # as space changes confuse LLDB.
            innerTypeName = hashTypeName.replace("QHash", "QHashNode", 1)
667 668 669 670 671 672 673
            node = value["i"].cast(d.lookupType(innerTypeName).pointer()).dereference()
            key = node["key"]
            if not key:
                # LLDB can't access directly since it's in anonymous union
                # for Qt4 optimized int keytype
                key = node[1]["key"]
            d.putSubItem("key", key)
674 675 676 677 678 679 680 681 682
            d.putSubItem("value", node["value"])

def qdump__QHash__const_iterator(d, value):
    qHashIteratorHelper(d, value)

def qdump__QHash__iterator(d, value):
    qHashIteratorHelper(d, value)


hjk's avatar
hjk committed
683
def qdump__QHostAddress(d, value):
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
    # QHostAddress in Qt 4.5 (byte offsets)
    #   quint32 a        (0)
    #   Q_IPV6ADDR a6    (4)
    #   protocol         (20)
    #   QString ipString (24)
    #   QString scopeId  (24 + ptrSize)
    #   bool isParsed    (24 + 2 * ptrSize)
    # QHostAddress in Qt 5.0
    #   QString ipString (0)
    #   QString scopeId  (ptrSize)
    #   quint32 a        (2*ptrSize)
    #   Q_IPV6ADDR a6    (2*ptrSize + 4)
    #   protocol         (2*ptrSize + 20)
    #   bool isParsed    (2*ptrSize + 24)

699
    privAddress = d.extractPointer(value)
700
    isQt5 = d.qtVersion() >= 0x050000
701
    sizeofQString = d.ptrSize()
702
    ipStringAddress = privAddress + (0 if isQt5 else 24)
703
    isParsedAddress = privAddress + 24 + 2 * sizeofQString
704
    # value.d.d->ipString
hjk's avatar
hjk committed
705
    ipString = d.encodeString(ipStringAddress, limit=100)
706
    if d.extractByte(isParsedAddress) and len(ipString) > 0:
707
        d.putValue(ipString, Hex4EncodedLittleEndian)
hjk's avatar
hjk committed
708
    else:
709 710 711 712 713 714 715
        # value.d.d->protocol:
        #  QAbstractSocket::IPv4Protocol = 0
        #  QAbstractSocket::IPv6Protocol = 1
        protoAddress = privAddress + 20 + (2 * sizeofQString if isQt5 else 0);
        proto = d.extractInt(protoAddress)
        if proto == 1:
            # value.d.d->a6
716 717
            a6Offset = 4 + (2 * sizeofQString if isQt5 else 0)
            data = d.readMemory(privAddress + a6Offset, 16)
718 719
            address = ':'.join("%x" % int(data[i:i+4], 16) for i in xrange(0, 32, 4))
            scopeId = privAddress + sizeofQString + (0 if isQt5 else 24)
hjk's avatar
hjk committed
720
            scopeId = d.encodeString(scopeId, limit=100)
721 722 723 724 725 726 727 728 729 730 731 732
            d.putValue("%s%%%s" % (address, scopeId), IPv6AddressAndHexScopeId)
        elif proto == 0:
            # value.d.d->a
            a = d.extractInt(privAddress + (2 * sizeofQString if isQt5 else 0))
            a, n4 = divmod(a, 256)
            a, n3 = divmod(a, 256)
            a, n2 = divmod(a, 256)
            a, n1 = divmod(a, 256)
            d.putValue("%d.%d.%d.%d" % (n1, n2, n3, n4));
        else:
            d.putValue("<unspecified>")

733 734
    d.putPlainChildren(value["d"]["d"].dereference())

hjk's avatar
hjk committed
735

736
def qdump__QIPv6Address(d, value):
737 738 739 740 741 742 743 744 745 746 747
    #warn("IPV6.VALUE: %s" % value)
    #warn("IPV6.ADDR: 0x%x" % d.addressOf(value))
    #warn("IPV6.LOADADDR: 0x%x" % value.GetLoadAddress())
    c = value["c"]
    data = d.readMemory(d.addressOf(c), 16)
    d.putValue(':'.join("%x" % int(data[i:i+4], 16) for i in xrange(0, 32, 4)))
    #d.putValue('xx')
    #d.putValue("0x%x - 0x%x" % (d.addressOf(value), d.addressOf(c)))
    #d.putValue("0x%x - 0x%x" % (value.GetAddress(), c.GetAddress()))
    #d.putValue("0x%x - 0x%x" % (value.GetLoadAddress(), c.GetLoadAddress()))
    d.putPlainChildren(c)
748

749
def qform__QList():
750
    return [DirectQListStorageFormat, IndirectQListStorageFormat]
751

hjk's avatar
hjk committed
752
def qdump__QList(d, value):
753 754 755 756 757 758
    base = d.extractPointer(value)
    begin = d.extractInt(base + 8)
    end = d.extractInt(base + 12)
    array = base + 16
    if d.qtVersion() < 0x50000:
        array += d.ptrSize()
759
    d.check(begin >= 0 and end >= 0 and end <= 1000 * 1000 * 1000)
760
    size = end - begin
761
    d.check(size >= 0)
762
    #d.checkRef(private["ref"])
hjk's avatar
hjk committed
763

764
    innerType = d.templateArgument(value.type, 0)
hjk's avatar
hjk committed
765

766
    d.putItemCount(size)
hjk's avatar
hjk committed
767
    if d.isExpanded():
hjk's avatar
hjk committed
768
        innerSize = innerType.sizeof
769 770
        stepSize = d.ptrSize()
        addr = array + begin * stepSize
hjk's avatar
hjk committed
771 772 773 774 775
        # The exact condition here is:
        #  QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic
        # but this data is available neither in the compiled binary nor
        # in the frontend.
        # So as first approximation only do the 'isLarge' check:
776 777
        displayFormat = d.currentItemFormat()
        if displayFormat == DirectQListStorageFormat:
778
            isInternal = True
779
        elif displayFormat == IndirectQListStorageFormat:
780 781 782
            isInternal = False
        else:
            isInternal = innerSize <= stepSize and d.isMovableType(innerType)
783 784
        if isInternal:
            if innerSize == stepSize:
785
                d.putArrayData(addr, size, innerType)
786 787 788
            else:
                with Children(d, size, childType=innerType):
                    for i in d.childRange():
789 790
                        p = d.createValue(addr + i * stepSize, innerType)
                        d.putSubItem(i, p)
791
        else:
792 793 794
            # about 0.5s / 1000 items
            with Children(d, size, maxNumChild=2000, childType=innerType):
                for i in d.childRange():
795 796 797
                    p = d.extractPointer(addr + i * stepSize)
                    x = d.createValue(p, innerType)
                    d.putSubItem(i, x)
hjk's avatar
hjk committed
798

hjk's avatar
hjk committed
799
def qform__QImage():
800
    return [SimpleFormat, SeparateFormat]
hjk's avatar
hjk committed
801

hjk's avatar
hjk committed
802
def qdump__QImage(d, value):
803 804 805 806
    # This relies on current QImage layout:
    # QImageData:
    # - QAtomicInt ref
    # - int width, height, depth, nbytes
807 808 809 810
    # - padding on 64 bit machines
    # - qreal devicePixelRatio  (+20 + padding)  # Assume qreal == double, Qt 5 only
    # - QVector<QRgb> colortable (+20 + padding + gap)
    # - uchar *data (+20 + padding + gap + ptr)
811
    # [- uchar **jumptable jumptable with Qt 3 suppor]
812
    # - enum format (+20 + padding + gap + 2 * ptr)
813 814 815 816

    ptrSize = d.ptrSize()
    isQt5 = d.qtVersion() >= 0x050000
    offset = (3 if isQt5 else 2) * ptrSize
817
    base = d.extractPointer(d.addressOf(value) + offset)
818 819 820 821
    if base == 0:
        d.putValue("(invalid)")
        return
    qt3Support = d.isQt3Support()
822 823 824
    width = d.extractInt(base + 4)
    height = d.extractInt(base + 8)
    nbytes = d.extractInt(base + 16)
825
    padding = d.ptrSize() - d.intSize()
826
    pixelRatioSize = 8 if isQt5 else 0
827
    jumpTableSize = ptrSize if qt3Support else 0
828
    bits = d.extractPointer(base + 20 + padding + pixelRatioSize + ptrSize)
829
    iformat = d.extractInt(base + 20 + padding + pixelRatioSize + jumpTableSize + 2 * ptrSize)
830
    d.putValue("(%dx%d)" % (width, height))
831
    d.putNumChild(1)
hjk's avatar
hjk committed
832
    if d.isExpanded():
833
        with Children(d):
834 835 836 837
            d.putIntItem("width", width)
            d.putIntItem("height", height)
            d.putIntItem("nbytes", nbytes)
            d.putIntItem("format", iformat)
hjk's avatar
hjk committed
838
            with SubItem(d, "data"):
839
                d.putValue("0x%x" % bits)
840
                d.putNumChild(0)
841 842
                d.putType("void *")

843
    displayFormat = d.currentItemFormat()
844
    if displayFormat == SeparateFormat:
845 846 847 848 849 850 851 852 853 854 855
        # This is critical for performance. Writing to an external
        # file using the following is faster when using GDB.
        #   file = tempfile.mkstemp(prefix="gdbpy_")
        #   filename = file[1].replace("\\", "\\\\")
        #   gdb.execute("dump binary memory %s %s %s" %
        #       (filename, bits, bits + nbytes))
        #   d.putDisplay(DisplayImageFile, " %d %d %d %d %s"
        #       % (width, height, nbytes, iformat, filename))
        d.putField("editformat", DisplayImageData)
        d.put('editvalue="')
        d.put('%08x%08x%08x%08x' % (width, height, nbytes, iformat))
856
        d.put(d.readMemory(bits, nbytes))
857
        d.put('",')
hjk's avatar
hjk committed
858 859


hjk's avatar
hjk committed
860
def qdump__QLinkedList(d, value):
861
    dd = d.extractPointer(value)
hjk's avatar
hjk committed
862 863 864
    ptrSize = d.ptrSize()
    n = d.extractInt(dd + 4 + 2 * ptrSize);
    ref = d.extractInt(dd + 2 * ptrSize);
865 866
    d.check(0 <= n and n <= 100*1000*1000)
    d.check(-1 <= ref and ref <= 1000)
hjk's avatar
hjk committed
867
    d.putItemCount(n)
hjk's avatar
hjk committed
868
    if d.isExpanded():
869
        innerType = d.templateArgument(value.type, 0)
hjk's avatar
hjk committed
870
        with Children(d, n, maxNumChild=1000, childType=innerType):
871
            pp = d.extractPointer(dd)
872
            for i in d.childRange():
hjk's avatar
hjk committed
873
                d.putSubItem(i, d.createValue(pp + 2 * ptrSize, innerType))
874
                pp = d.extractPointer(pp)