File indexing completed on 2025-01-05 05:23:52
0001 /* 0002 This file is part of the Okteta Kasten module, made within the KDE community. 0003 0004 SPDX-FileCopyrightText: 2007-2008 Friedrich W. H. Kossebau <kossebau@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0007 */ 0008 0009 #include "bytearraysourcecodestreamencoder.hpp" 0010 0011 // Okteta core 0012 #include <Okteta/AbstractByteArrayModel> 0013 // KF 0014 #include <KConfigGroup> 0015 #include <KSharedConfig> 0016 #include <KLocalizedString> 0017 // Qt 0018 #include <QTextStream> 0019 // Std 0020 #include <array> 0021 #include <algorithm> 0022 #include <iterator> 0023 0024 static constexpr int primitiveDataTypeCount = 0025 static_cast<int>(Kasten::SourceCodeStreamEncoderSettings::PrimitiveDataType::_Count); 0026 static const std::array<QString, primitiveDataTypeCount> primitiveDataTypeConfigValueList = { 0027 QStringLiteral("Char"), 0028 QStringLiteral("UnsignedChar"), 0029 QStringLiteral("Short"), 0030 QStringLiteral("UnsignedShort"), 0031 QStringLiteral("Integer"), 0032 QStringLiteral("UnsignedInteger"), 0033 QStringLiteral("Float"), 0034 QStringLiteral("Double"), 0035 }; 0036 0037 0038 template <> 0039 inline Kasten::SourceCodeStreamEncoderSettings::PrimitiveDataType KConfigGroup::readEntry(const char *key, 0040 const Kasten::SourceCodeStreamEncoderSettings::PrimitiveDataType &defaultValue) const 0041 { 0042 const QString entry = readEntry(key, QString()); 0043 0044 auto it = std::find(primitiveDataTypeConfigValueList.cbegin(), primitiveDataTypeConfigValueList.cend(), entry); 0045 if (it == primitiveDataTypeConfigValueList.cend()) { 0046 return defaultValue; 0047 } 0048 0049 const int listIndex = std::distance(primitiveDataTypeConfigValueList.cbegin(), it); 0050 return static_cast<Kasten::SourceCodeStreamEncoderSettings::PrimitiveDataType>(listIndex); 0051 } 0052 0053 template <> 0054 inline void KConfigGroup::writeEntry(const char *key, 0055 const Kasten::SourceCodeStreamEncoderSettings::PrimitiveDataType &value, 0056 KConfigBase::WriteConfigFlags flags) 0057 { 0058 const int listIndex = static_cast<int>(value); 0059 writeEntry(key, primitiveDataTypeConfigValueList[listIndex], flags); 0060 } 0061 0062 namespace Kasten { 0063 0064 const QString SourceCodeStreamEncoderSettings::DefaultVariableName = QStringLiteral("array"); 0065 0066 static constexpr const char* PrimitiveDataTypeName[] = { 0067 "char", 0068 "unsigned char", 0069 "short", 0070 "unsigned short", 0071 "int", 0072 "unsigned int", 0073 "float", 0074 "double" 0075 }; 0076 0077 static constexpr int SizeOfPrimitiveDataType[] = 0078 { 0079 sizeof(char), 0080 sizeof(unsigned char), 0081 sizeof(short), 0082 sizeof(unsigned short), 0083 sizeof(int), 0084 sizeof(unsigned int), 0085 sizeof(float), 0086 sizeof(double) 0087 }; 0088 0089 static constexpr int NoOfPrimitiveDataTypes = 8; 0090 0091 inline QString decimalFormattedNumberPlaceHolder() { return QStringLiteral("%1"); } 0092 inline QString hexadecimalFormattedNumberPlaceHolder() { return QStringLiteral("0x%1"); } 0093 0094 SourceCodeStreamEncoderSettings::SourceCodeStreamEncoderSettings() = default; 0095 0096 bool SourceCodeStreamEncoderSettings::operator==(const SourceCodeStreamEncoderSettings& other) const 0097 { 0098 return 0099 (variableName == other.variableName) && 0100 (dataType == other.dataType) && 0101 (elementsPerLine == other.elementsPerLine) && 0102 (unsignedAsHexadecimal == other.unsignedAsHexadecimal); 0103 } 0104 0105 void SourceCodeStreamEncoderSettings::loadConfig(const KConfigGroup& configGroup) 0106 { 0107 variableName = configGroup.readEntry(VariableNameConfigKey, DefaultVariableName); 0108 dataType = configGroup.readEntry(DataTypeConfigKey, DefaultDataType); 0109 elementsPerLine = configGroup.readEntry(ElementsPerLineConfigKey, DefaultElementsPerLine); 0110 unsignedAsHexadecimal = configGroup.readEntry(UnsignedAsHexadecimalConfigKey, DefaultUnsignedAsHexadecimal); 0111 } 0112 0113 void SourceCodeStreamEncoderSettings::saveConfig(KConfigGroup& configGroup) const 0114 { 0115 configGroup.writeEntry(VariableNameConfigKey, variableName); 0116 configGroup.writeEntry(DataTypeConfigKey, dataType); 0117 configGroup.writeEntry(ElementsPerLineConfigKey, elementsPerLine); 0118 configGroup.writeEntry(UnsignedAsHexadecimalConfigKey, unsignedAsHexadecimal); 0119 } 0120 0121 ByteArraySourceCodeStreamEncoder::ByteArraySourceCodeStreamEncoder() 0122 : AbstractByteArrayStreamEncoder(i18nc("name of the encoding target", "C Array"), QStringLiteral("text/x-csrc")) 0123 { 0124 const KConfigGroup configGroup(KSharedConfig::openConfig(), ConfigGroupId); 0125 mSettings.loadConfig(configGroup); 0126 } 0127 0128 ByteArraySourceCodeStreamEncoder::~ByteArraySourceCodeStreamEncoder() = default; 0129 0130 const char* const* ByteArraySourceCodeStreamEncoder::dataTypeNames() const { return PrimitiveDataTypeName; } 0131 int ByteArraySourceCodeStreamEncoder::dataTypesCount() const { return NoOfPrimitiveDataTypes; } 0132 0133 void ByteArraySourceCodeStreamEncoder::setSettings(const SourceCodeStreamEncoderSettings& settings) 0134 { 0135 if (mSettings == settings) { 0136 return; 0137 } 0138 0139 mSettings = settings; 0140 KConfigGroup configGroup(KSharedConfig::openConfig(), ConfigGroupId); 0141 mSettings.saveConfig(configGroup); 0142 Q_EMIT settingsChanged(); 0143 } 0144 0145 bool ByteArraySourceCodeStreamEncoder::encodeDataToStream(QIODevice* device, 0146 const ByteArrayView* byteArrayView, 0147 const Okteta::AbstractByteArrayModel* byteArrayModel, 0148 const Okteta::AddressRange& range) 0149 { 0150 Q_UNUSED(byteArrayView) 0151 0152 bool success = true; 0153 0154 // encode 0155 QTextStream textStream(device); 0156 0157 // textStream << "// from File , selection \n"; 0158 0159 const int size = range.width(); 0160 const int dataTypeSize = SizeOfPrimitiveDataType[static_cast<int>(mSettings.dataType)]; 0161 const int sizeOfArray = (size + dataTypeSize - 1) / dataTypeSize; 0162 0163 textStream << "const " << QLatin1String(PrimitiveDataTypeName[static_cast<int>(mSettings.dataType)]) << ' ' 0164 << mSettings.variableName << '[' << sizeOfArray << "] =" << Qt::endl 0165 << '{' << Qt::endl; 0166 0167 int elementAddedOnLine = 0; 0168 for (Okteta::Address i = range.start(); i <= range.end(); i += dataTypeSize) { 0169 if (elementAddedOnLine == 0) { 0170 textStream << " "; // just 3, one space before every datum 0171 } 0172 textStream << ' ' << printFormatted(byteArrayModel, i, range.end() - i + 1); 0173 if (i + dataTypeSize <= range.end()) { 0174 textStream << ','; 0175 } 0176 0177 if (++elementAddedOnLine >= mSettings.elementsPerLine) { 0178 textStream << Qt::endl; 0179 elementAddedOnLine = 0; 0180 } 0181 } 0182 0183 if (elementAddedOnLine > 0) { 0184 textStream << Qt::endl; 0185 } 0186 0187 textStream << "};" << Qt::endl; 0188 0189 return success; 0190 } 0191 0192 QString ByteArraySourceCodeStreamEncoder::printFormatted(const Okteta::AbstractByteArrayModel* byteArrayModel, Okteta::Address offset, 0193 unsigned int dataSize) const 0194 { 0195 QString result; 0196 switch (mSettings.dataType) 0197 { 0198 case SourceCodeStreamEncoderSettings::PrimitiveDataType::Char: 0199 { 0200 char e = 0; 0201 byteArrayModel->copyTo(reinterpret_cast<Okteta::Byte*>(&e), offset, qMin<size_t>(sizeof(e), dataSize)); 0202 constexpr int fieldWidth = 4; 0203 result = decimalFormattedNumberPlaceHolder().arg((int)e, fieldWidth); 0204 break; 0205 } 0206 case SourceCodeStreamEncoderSettings::PrimitiveDataType::UnsignedChar: 0207 { 0208 unsigned char e = 0; 0209 byteArrayModel->copyTo(reinterpret_cast<Okteta::Byte*>(&e), offset, qMin(uint(sizeof(e)), dataSize)); 0210 const int base = mSettings.unsignedAsHexadecimal ? 16 : 10; 0211 const int fieldWidth = mSettings.unsignedAsHexadecimal ? 2 : 3; 0212 const QString formattedNumberPlaceHolder = mSettings.unsignedAsHexadecimal ? 0213 hexadecimalFormattedNumberPlaceHolder() : decimalFormattedNumberPlaceHolder(); 0214 const QChar stuffChar = QLatin1Char(mSettings.unsignedAsHexadecimal ? '0' : ' '); 0215 result = formattedNumberPlaceHolder.arg(e, fieldWidth, base, stuffChar); 0216 break; 0217 } 0218 case SourceCodeStreamEncoderSettings::PrimitiveDataType::Short: 0219 { 0220 short e = 0; 0221 byteArrayModel->copyTo(reinterpret_cast<Okteta::Byte*>(&e), offset, qMin(uint(sizeof(e)), dataSize)); 0222 constexpr int fieldWidth = 6; 0223 result = decimalFormattedNumberPlaceHolder().arg(e, fieldWidth); 0224 break; 0225 } 0226 case SourceCodeStreamEncoderSettings::PrimitiveDataType::UnsignedShort: 0227 { 0228 unsigned short e = 0; 0229 byteArrayModel->copyTo(reinterpret_cast<Okteta::Byte*>(&e), offset, qMin(uint(sizeof(e)), dataSize)); 0230 const int base = mSettings.unsignedAsHexadecimal ? 16 : 10; 0231 const int fieldWidth = mSettings.unsignedAsHexadecimal ? 4 : 5; 0232 const QString formattedNumberPlaceHolder = mSettings.unsignedAsHexadecimal ? 0233 hexadecimalFormattedNumberPlaceHolder() : decimalFormattedNumberPlaceHolder(); 0234 const QChar stuffChar = QLatin1Char(mSettings.unsignedAsHexadecimal ? '0' : ' '); 0235 result = formattedNumberPlaceHolder.arg(e, fieldWidth, base, stuffChar); 0236 break; 0237 } 0238 case SourceCodeStreamEncoderSettings::PrimitiveDataType::Integer: 0239 { 0240 int e = 0; 0241 byteArrayModel->copyTo(reinterpret_cast<Okteta::Byte*>(&e), offset, qMin(uint(sizeof(e)), dataSize)); 0242 constexpr int fieldWidth = 11; 0243 result = decimalFormattedNumberPlaceHolder().arg(e, fieldWidth); 0244 break; 0245 } 0246 case SourceCodeStreamEncoderSettings::PrimitiveDataType::UnsignedInteger: 0247 { 0248 unsigned int e = 0; 0249 byteArrayModel->copyTo(reinterpret_cast<Okteta::Byte*>(&e), offset, qMin(uint(sizeof(e)), dataSize)); 0250 const int base = mSettings.unsignedAsHexadecimal ? 16 : 10; 0251 const int fieldWidth = mSettings.unsignedAsHexadecimal ? 8 : 10; 0252 const QString formattedNumberPlaceHolder = mSettings.unsignedAsHexadecimal ? 0253 hexadecimalFormattedNumberPlaceHolder() : decimalFormattedNumberPlaceHolder(); 0254 const QChar stuffChar = QLatin1Char(mSettings.unsignedAsHexadecimal ? '0' : ' '); 0255 result = formattedNumberPlaceHolder.arg(e, fieldWidth, base, stuffChar); 0256 break; 0257 } 0258 case SourceCodeStreamEncoderSettings::PrimitiveDataType::Float: 0259 { 0260 float e = 0; 0261 byteArrayModel->copyTo(reinterpret_cast<Okteta::Byte*>(&e), offset, qMin(uint(sizeof(e)), dataSize)); 0262 constexpr int fieldWidth = 13; 0263 result = decimalFormattedNumberPlaceHolder().arg(e, fieldWidth); 0264 break; 0265 } 0266 case SourceCodeStreamEncoderSettings::PrimitiveDataType::Double: 0267 { 0268 double e = 0; 0269 byteArrayModel->copyTo(reinterpret_cast<Okteta::Byte*>(&e), offset, qMin(uint(sizeof(e)), dataSize)); 0270 constexpr int fieldWidth = 13; 0271 result = decimalFormattedNumberPlaceHolder().arg(e, fieldWidth); 0272 break; 0273 } 0274 case SourceCodeStreamEncoderSettings::PrimitiveDataType::_Count: 0275 // dummy entry to avoid compiler warning -Wswitch, can this be avoided? 0276 break; 0277 } 0278 0279 return result; 0280 } 0281 0282 } 0283 0284 #include "moc_bytearraysourcecodestreamencoder.cpp"