1 /*
2     This file is part of the Okteta Kasten Framework, made within the KDE community.
3 
4     SPDX-FileCopyrightText: 2011 Alex Richardson <alex.richardson@gmx.de>
5 
6     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8 
9 #include "flagdatainformation.hpp"
10 #include <QVarLengthArray>
11 #include <KLocalizedString>
12 
FlagDataInformation(const QString & name,PrimitiveDataInformation * type,const EnumDefinition::Ptr & enumDef,DataInformation * parent)13 FlagDataInformation::FlagDataInformation(const QString& name, PrimitiveDataInformation* type,
14                                          const EnumDefinition::Ptr& enumDef, DataInformation* parent)
15     : EnumDataInformation(name, type, enumDef, parent)
16 {
17     Q_ASSERT_X(type->type() != PrimitiveDataType::Double && type->type() != PrimitiveDataType::Float && type->type() != PrimitiveDataType::Invalid,
18                "FlagDataInformation::FlagDataInformation", "Bitflags only work with integers!");
19 }
20 
21 using FlagPair = QPair<QString, quint64>;
22 
23 template <typename T, int len>
removeFromArray(QVarLengthArray<T,len> & array,int index)24 static void removeFromArray(QVarLengthArray<T, len>& array, int index)
25 {
26     Q_ASSERT(index >= 0 && index < array.size());
27     int max = array.size() - 1;
28     for (int i = index; i < max; ++i) {
29         array[i] = array[i + 1];
30     }
31 
32     array.removeLast();
33 }
34 
valueStringImpl() const35 QString FlagDataInformation::valueStringImpl() const
36 {
37     Q_ASSERT(mWasAbleToRead);
38     QMapIterator<AllPrimitiveTypes, QString> iter(mEnum->values());
39     // I doubt more than 10 flags will be set very often -> only then do we need a malloc
40     QVarLengthArray<FlagPair, 10> arr;
41     const quint64 value = mValue->value().value<quint64>();
42     while (iter.hasNext()) {
43         iter.next();
44         const quint64 flag = iter.key().value<quint64>();
45         if ((value & flag) == flag) {
46             // flag is set
47             arr.append(qMakePair(iter.value(), flag));
48         }
49     }
50 
51     // now we have all flags, check if some overlap
52     for (int i = 0; i < arr.size(); ++i) {
53         const quint64 firstFlag = arr.at(i).second;
54         for (int j = 0; j < arr.size();) {
55             if (j == i) {
56                 j++;
57                 continue;
58             }
59             // check if they overlap
60             quint64 secondFlag = arr.at(j).second;
61             if ((firstFlag & secondFlag) == secondFlag) {
62                 // they overlap, remove the second flag
63                 removeFromArray(arr, j);
64                 if (j < i) {
65                     i--; // i was pushed back by one as well
66                 }
67             } else {
68                 j++;
69             }
70         }
71     }
72 
73     // if array has zero elements just return the value in hexadecimal
74     if (arr.isEmpty()) {
75         return i18n("0x%1 (no matching flags)", QString::number(value, 16));
76     }
77 
78     // make sure all we also show remaining bits at the end
79     quint64 usedBits = 0;
80     QString result;
81     for (int i = 0, size = arr.size(); i < size; ++i) {
82         if (i != 0) {
83             result += QLatin1String(" | ");
84         }
85         result += arr.at(i).first;
86         usedBits |= arr.at(i).second;
87     }
88 
89     // TODO remove a NONE flag if others present (value = 0)
90 
91     // TODO set invalid if value not completely covered by flags
92 
93     if (usedBits != value) {
94         quint64 missing = value & ~usedBits;
95         result += QLatin1String(" | 0x") + QString::number(missing, 16);
96     }
97 
98     return result;
99 }
100 
typeNameImpl() const101 QString FlagDataInformation::typeNameImpl() const
102 {
103     return i18nc("Displayed in the type column. first comes the name "
104                  "of the enum, then the underlying type (e.g. uint32)",
105                  "flag %1 (%2)", mEnum->name(), mValue->typeName());
106 }
107