File indexing completed on 2025-01-19 05:20:19
0001 /* 0002 This file is part of the Okteta Kasten module, made within the KDE community. 0003 0004 SPDX-FileCopyrightText: 2010 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 "bytearrayuuencodingstreamencoder.hpp" 0010 0011 // lib 0012 #include "../base64/bytearraybase64streamencoder.hpp" 0013 // Okteta core 0014 #include <Okteta/AbstractByteArrayModel> 0015 // KF 0016 #include <KConfigGroup> 0017 #include <KSharedConfig> 0018 #include <KLocalizedString> 0019 // Qt 0020 #include <QTextStream> 0021 0022 template <> 0023 inline Kasten::UuencodingStreamEncoderSettings::EncodingType 0024 KConfigGroup::readEntry(const char *key, 0025 const Kasten::UuencodingStreamEncoderSettings::EncodingType &defaultValue) const 0026 { 0027 const QString entry = readEntry(key, QString()); 0028 const Kasten::UuencodingStreamEncoderSettings::EncodingType encodingType = 0029 (entry == QLatin1String("Historical")) ? 0030 Kasten::UuencodingStreamEncoderSettings::EncodingType::Historical : 0031 (entry == QLatin1String("Base64")) ? 0032 Kasten::UuencodingStreamEncoderSettings::EncodingType::Base64 : 0033 /* else */ defaultValue; 0034 return encodingType; 0035 } 0036 0037 template <> 0038 inline void KConfigGroup::writeEntry(const char *key, 0039 const Kasten::UuencodingStreamEncoderSettings::EncodingType &value, 0040 KConfigBase::WriteConfigFlags flags) 0041 { 0042 const QString valueString = 0043 (value == Kasten::UuencodingStreamEncoderSettings::EncodingType::Historical) ? 0044 QLatin1String("Historical") : QLatin1String("Base64"); 0045 writeEntry(key, valueString, flags); 0046 } 0047 0048 namespace Kasten { 0049 0050 const QString UuencodingStreamEncoderSettings::DefaultFileName = QStringLiteral("okteta-export"); 0051 0052 static inline constexpr char uumapByteHistorical(char byte) { return (byte > 0) ? (byte + 32) : '`'; } 0053 static inline char uumapByteBase64(char byte) { return base64EncodeMap[(int)byte]; } 0054 0055 struct UumapEncodeData 0056 { 0057 char (* mapByte)(char); 0058 const char* header; 0059 const char* footer; 0060 const char* paddingData[2]; 0061 bool hasLength; 0062 0063 inline const char* padding(ByteArrayUuencodingStreamEncoder::InputByteIndex index) const 0064 { 0065 return paddingData[static_cast<int>(index) - 1]; 0066 } 0067 }; 0068 0069 static constexpr UumapEncodeData historicalUumapEncodeData = 0070 { 0071 &uumapByteHistorical, 0072 "begin", 0073 "\n`\nend\n", 0074 {"``", "`"}, 0075 true 0076 }; 0077 0078 static constexpr UumapEncodeData base64UumapEncodeData = 0079 { 0080 &uumapByteBase64, 0081 "begin-base64", 0082 "\n====\n", 0083 {"==", "="}, 0084 false 0085 }; 0086 0087 UuencodingStreamEncoderSettings::UuencodingStreamEncoderSettings() = default; 0088 0089 bool UuencodingStreamEncoderSettings::operator==(const UuencodingStreamEncoderSettings& other) const 0090 { 0091 return (fileName == other.fileName) && (encodingType == other.encodingType); 0092 } 0093 0094 void UuencodingStreamEncoderSettings::loadConfig(const KConfigGroup& configGroup) 0095 { 0096 fileName = configGroup.readEntry(FileNameConfigKey, DefaultFileName); 0097 encodingType = configGroup.readEntry(EncodingTypeConfigKey, DefaultEncodingType); 0098 } 0099 0100 void UuencodingStreamEncoderSettings::saveConfig(KConfigGroup& configGroup) const 0101 { 0102 configGroup.writeEntry(FileNameConfigKey, fileName); 0103 configGroup.writeEntry(EncodingTypeConfigKey, encodingType); 0104 } 0105 0106 0107 ByteArrayUuencodingStreamEncoder::ByteArrayUuencodingStreamEncoder() 0108 : AbstractByteArrayStreamEncoder(i18nc("name of the encoding target", "Uuencoding"), QStringLiteral("text/x-uuencode")) 0109 { 0110 const KConfigGroup configGroup(KSharedConfig::openConfig(), ConfigGroupId); 0111 mSettings.loadConfig(configGroup); 0112 } 0113 0114 ByteArrayUuencodingStreamEncoder::~ByteArrayUuencodingStreamEncoder() = default; 0115 0116 void ByteArrayUuencodingStreamEncoder::setSettings(const UuencodingStreamEncoderSettings& settings) 0117 { 0118 if (mSettings == settings) { 0119 return; 0120 } 0121 0122 mSettings = settings; 0123 KConfigGroup configGroup(KSharedConfig::openConfig(), ConfigGroupId); 0124 mSettings.saveConfig(configGroup); 0125 Q_EMIT settingsChanged(); 0126 } 0127 0128 bool ByteArrayUuencodingStreamEncoder::encodeDataToStream(QIODevice* device, 0129 const ByteArrayView* byteArrayView, 0130 const Okteta::AbstractByteArrayModel* byteArrayModel, 0131 const Okteta::AddressRange& range) 0132 { 0133 Q_UNUSED(byteArrayView); 0134 0135 bool success = true; 0136 0137 // encode 0138 QTextStream textStream(device); 0139 0140 // prepare 0141 InputByteIndex inputByteIndex = InputByteIndex::First; 0142 int inputGroupsPerLine = 0; 0143 unsigned char bitsFromLastByte; 0144 0145 const UumapEncodeData* encodeData = 0146 (mSettings.encodingType == UuencodingStreamEncoderSettings::EncodingType::Historical) ? 0147 &historicalUumapEncodeData : 0148 /* else */ 0149 &base64UumapEncodeData; 0150 0151 // header 0152 textStream << encodeData->header << " 644 " << mSettings.fileName.toLatin1(); 0153 0154 const int firstLineLength = qMin(range.width(), uuInputLineLength); 0155 if (firstLineLength > 0) { 0156 textStream << '\n'; 0157 if (encodeData->hasLength) { 0158 textStream << encodeData->mapByte(firstLineLength); 0159 } 0160 } 0161 0162 for (Okteta::Address i = range.start(); i <= range.end(); ++i) { 0163 const Okteta::Byte byte = byteArrayModel->byte(i); 0164 0165 switch (inputByteIndex) 0166 { 0167 case InputByteIndex::First: 0168 // bits 7..2 0169 textStream << encodeData->mapByte(byte >> 2); 0170 // bits 1..0 -> 5..4 for next 0171 bitsFromLastByte = (byte & 0x3) << 4; 0172 inputByteIndex = InputByteIndex::Second; 0173 break; 0174 case InputByteIndex::Second: 0175 // from last and bits 7..4 as 3..0 from this 0176 textStream << encodeData->mapByte(bitsFromLastByte | byte >> 4); 0177 // bits 3..0 -> 5..2 for next 0178 bitsFromLastByte = (byte & 0xf) << 2; 0179 inputByteIndex = InputByteIndex::Third; 0180 break; 0181 case InputByteIndex::Third: 0182 // from last and bits 7..6 as 1..0 from this 0183 textStream << encodeData->mapByte(bitsFromLastByte | byte >> 6); 0184 // bits 5..0 0185 textStream << encodeData->mapByte(byte & 0x3F); 0186 inputByteIndex = InputByteIndex::First; 0187 ++inputGroupsPerLine; 0188 if (inputGroupsPerLine >= maxInputGroupsPerLine && i < range.end()) { 0189 const int remainsCount = range.end() - i; 0190 const int nextLineLength = qMin(remainsCount, uuInputLineLength); 0191 textStream << '\n'; 0192 if (encodeData->hasLength) { 0193 textStream << encodeData->mapByte(nextLineLength); 0194 } 0195 inputGroupsPerLine = 0; 0196 } 0197 break; 0198 } 0199 } 0200 0201 const bool hasBitsLeft = (inputByteIndex != InputByteIndex::First); 0202 if (hasBitsLeft) { 0203 textStream << encodeData->mapByte(bitsFromLastByte) 0204 << encodeData->padding(inputByteIndex); 0205 } 0206 // footer 0207 textStream << encodeData->footer; 0208 0209 return success; 0210 } 0211 0212 } 0213 0214 #include "moc_bytearrayuuencodingstreamencoder.cpp"