From 23b7dc5b5c1c68df28e162ebdf33873480f24f78 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@digia.com>
Date: Fri, 18 Jan 2013 14:19:20 +0100
Subject: [PATCH] CDB: Dump QStringRef.

Extend QString dumper to be able to dump a substring.

Change-Id: I1f64e441980a7c2c295f40317b2b187cfebcd7ea
Reviewed-by: hjk <qthjk@ovi.com>
---
 src/libs/qtcreatorcdbext/knowntype.h          |  1 +
 src/libs/qtcreatorcdbext/symbolgroupvalue.cpp | 60 +++++++++++++++----
 2 files changed, 48 insertions(+), 13 deletions(-)

diff --git a/src/libs/qtcreatorcdbext/knowntype.h b/src/libs/qtcreatorcdbext/knowntype.h
index 39e8c8cd501..9d197d345c7 100644
--- a/src/libs/qtcreatorcdbext/knowntype.h
+++ b/src/libs/qtcreatorcdbext/knowntype.h
@@ -71,6 +71,7 @@ enum KnownType
     KT_QVariant = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + KT_HasComplexDumper + 17,
     KT_QBasicAtomicInt = KT_Qt_Type + KT_HasSimpleDumper + 18,
     KT_QAtomicInt = KT_Qt_Type + KT_HasSimpleDumper + 19,
+    KT_QStringRef = KT_Qt_Type + KT_HasSimpleDumper + 20,
     KT_QObject = KT_Qt_Type + KT_HasSimpleDumper + KT_HasComplexDumper + 20,
     KT_QWindow = KT_Qt_Type + KT_HasSimpleDumper + KT_HasComplexDumper + 21,
     KT_QWidget = KT_Qt_Type + KT_HasSimpleDumper + KT_HasComplexDumper + 22,
diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
index 3016dfe2efa..d4bff299324 100644
--- a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
+++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
@@ -30,6 +30,10 @@
 // std::copy is perfectly fine, don't let MSVC complain about it being deprecated
 #pragma warning (disable: 4996)
 
+#ifndef NOMINMAX
+#  define NOMINMAX
+#endif
+
 #include "symbolgroupvalue.h"
 #include "symbolgroup.h"
 #include "stringutils.h"
@@ -38,6 +42,7 @@
 
 #include <iomanip>
 #include <algorithm>
+#include <limits>
 #include <ctype.h>
 
 typedef std::vector<int>::size_type VectorIndexType;
@@ -1263,6 +1268,8 @@ static KnownType knownClassTypeHelper(const std::string &type,
             return KT_QTransform;
         if (!type.compare(qPos, 10, "QFixedSize"))
             return KT_QFixedSize;
+        if (!type.compare(qPos, 10, "QStringRef"))
+            return KT_QStringRef;
         break;
     case 11:
         if (!type.compare(qPos, 11, "QStringList"))
@@ -1517,36 +1524,40 @@ QtStringAddressData readQtStringAddressData(const SymbolGroupValue &dV,
 
 // Retrieve data from a QByteArrayData(char)/QStringData(wchar_t)
 // in desired type. For empty arrays, no data are allocated.
+// All sizes are in CharType units. zeroTerminated means data are 0-terminated
+// in the data type, but "size" does not contain it.
 template <typename CharType>
 bool readQt5StringData(const SymbolGroupValue &dV, int qtMajorVersion,
-                       bool zeroTerminated, unsigned sizeLimit,
+                       bool zeroTerminated, unsigned position, unsigned sizeLimit,
                        unsigned *fullSize, unsigned *arraySize,
                        CharType **array)
 {
     *array = 0;
-    QtStringAddressData data = readQtStringAddressData(dV, qtMajorVersion);
-    *arraySize = *fullSize = data.size;
-    if (!data.address)
+    const QtStringAddressData data = readQtStringAddressData(dV, qtMajorVersion);
+    if (!data.address || position > data.size)
         return false;
+    const ULONG64 address = data.address + sizeof(CharType) * position;
+    *fullSize = data.size - position;
+    *arraySize = std::min(*fullSize, sizeLimit);
     if (!*fullSize)
         return true;
-    const bool truncated = *fullSize > sizeLimit;
-    *arraySize = truncated ?  sizeLimit : *fullSize;
     const unsigned memorySize =
             sizeof(CharType) * (*arraySize + (zeroTerminated ? 1 : 0));
     unsigned char *memory =
             SymbolGroupValue::readMemory(dV.context().dataspaces,
-                                         data.address, memorySize);
+                                         address, memorySize);
     if (!memory)
         return false;
     *array = reinterpret_cast<CharType *>(memory);
-    if (truncated && zeroTerminated)
+    if ((*arraySize < *fullSize) && zeroTerminated)
         *(*array + *arraySize) = CharType(0);
     return true;
 }
 
 static inline bool dumpQString(const SymbolGroupValue &v, std::wostream &str,
-                               MemoryHandle **memoryHandle = 0)
+                               MemoryHandle **memoryHandle = 0,
+                               unsigned position = 0,
+                               unsigned length = std::numeric_limits<unsigned>::max())
 {
     const QtInfo &qtInfo = QtInfo::get(v.context());
     const SymbolGroupValue dV = v["d"];
@@ -1557,7 +1568,11 @@ static inline bool dumpQString(const SymbolGroupValue &v, std::wostream &str,
         if (const SymbolGroupValue sizeValue = dV["size"]) {
             const int size = sizeValue.intValue();
             if (size >= 0) {
-                const std::wstring stringData = dV["data"].wcharPointerData(size);
+                std::wstring stringData = dV["data"].wcharPointerData(size);
+                if (position && position < stringData.size())
+                    stringData.erase(0, position);
+                if (length < stringData.size())
+                    stringData.erase(length, stringData.size() - length);
                 str << L'"' << stringData << L'"';
                 if (memoryHandle)
                     *memoryHandle = MemoryHandle::fromStdWString(stringData);
@@ -1574,11 +1589,13 @@ static inline bool dumpQString(const SymbolGroupValue &v, std::wostream &str,
     const SymbolGroupValue typeArrayV = dV[unsigned(0)];
     if (!typeArrayV)
         return false;
-    if (!readQt5StringData(typeArrayV, qtInfo.version, true, 10240, &fullSize, &size, &memory))
+    if (!readQt5StringData(typeArrayV, qtInfo.version, true, position,
+                           std::min(length, unsigned(10240)),
+                           &fullSize, &size, &memory))
         return false;
     if (size) {
         str << L'"' << memory;
-        if (fullSize > size)
+        if (std::min(fullSize, length) > size)
             str << L"...";
         str << L'"';
     } else {
@@ -1591,6 +1608,20 @@ static inline bool dumpQString(const SymbolGroupValue &v, std::wostream &str,
     return true;
 }
 
+static inline bool dumpQStringRef(const SymbolGroupValue &v, std::wostream &str,
+                                  MemoryHandle **memoryHandle = 0)
+{
+    const int position = v["m_position"].intValue();
+    const int size = v["m_size"].intValue();
+    if (position < 0 || size < 0)
+        return false;
+    const SymbolGroupValue string = v["m_string"];
+    if (!string || !dumpQString(string, str, memoryHandle, position, size))
+        return false;
+    str << L" (" << position << ',' << size << L')';
+    return true;
+}
+
 /* Pad a memory offset to align with pointer size */
 static inline unsigned padOffset(unsigned offset)
 {
@@ -1670,7 +1701,7 @@ static inline bool dumpQByteArray(const SymbolGroupValue &v, std::wostream &str,
     const SymbolGroupValue typeArrayV = dV[unsigned(0)];
     if (!typeArrayV)
         return false;
-    if (!readQt5StringData(typeArrayV, qtInfo.version, false, 10240, &fullSize, &size, &memory))
+    if (!readQt5StringData(typeArrayV, qtInfo.version, false, 0, 10240, &fullSize, &size, &memory))
         return false;
     if (size) {
         // Emulate CDB's behavior of replacing unprintable characters
@@ -2593,6 +2624,9 @@ unsigned dumpSimpleType(SymbolGroupNode  *n, const SymbolGroupValueContext &ctx,
     case KT_QString:
         rc = dumpQString(v, str, memoryHandleIn) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
         break;
+    case KT_QStringRef:
+        rc = dumpQStringRef(v, str, memoryHandleIn) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
+        break;
     case KT_QColor:
         rc = dumpQColor(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
         break;
-- 
GitLab