File indexing completed on 2025-01-05 05:23:53
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 "bytearrayxxencodingstreamencoder.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 0020 namespace Kasten { 0021 0022 const QString XxencodingStreamEncoderSettings::DefaultFileName; 0023 0024 static constexpr char xxencodeMap[64] = { 0025 '+', '-', '0', '1', '2', '3', '4', '5', 0026 '6', '7', '8', '9', 'A', 'B', 'C', 'D', 0027 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 0028 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 0029 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 0030 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 0031 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 0032 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' 0033 }; 0034 static constexpr const char* paddingData[2] = {"++", "+"}; 0035 0036 static inline constexpr char xxmapByte(char byte) { return xxencodeMap[static_cast<int>(byte)]; } 0037 0038 static inline constexpr const char* xxpadding(ByteArrayXxencodingStreamEncoder::InputByteIndex index) 0039 { 0040 return paddingData[static_cast<int>(index) - 1]; 0041 } 0042 0043 XxencodingStreamEncoderSettings::XxencodingStreamEncoderSettings() = default; 0044 0045 bool XxencodingStreamEncoderSettings::operator==(const XxencodingStreamEncoderSettings& other) const 0046 { 0047 return (fileName == other.fileName); 0048 } 0049 0050 void XxencodingStreamEncoderSettings::loadConfig(const KConfigGroup& configGroup) 0051 { 0052 fileName = configGroup.readEntry(FileNameConfigKey, DefaultFileName); 0053 } 0054 0055 void XxencodingStreamEncoderSettings::saveConfig(KConfigGroup& configGroup) const 0056 { 0057 configGroup.writeEntry(FileNameConfigKey, fileName); 0058 } 0059 0060 0061 ByteArrayXxencodingStreamEncoder::ByteArrayXxencodingStreamEncoder() 0062 : AbstractByteArrayStreamEncoder(i18nc("name of the encoding target", "Xxencoding"), QStringLiteral("text/x-xxencode")) 0063 { 0064 const KConfigGroup configGroup(KSharedConfig::openConfig(), ConfigGroupId); 0065 mSettings.loadConfig(configGroup); 0066 } 0067 0068 ByteArrayXxencodingStreamEncoder::~ByteArrayXxencodingStreamEncoder() = default; 0069 0070 void ByteArrayXxencodingStreamEncoder::setSettings(const XxencodingStreamEncoderSettings& settings) 0071 { 0072 if (mSettings == settings) { 0073 return; 0074 } 0075 0076 mSettings = settings; 0077 KConfigGroup configGroup(KSharedConfig::openConfig(), ConfigGroupId); 0078 mSettings.saveConfig(configGroup); 0079 Q_EMIT settingsChanged(); 0080 } 0081 0082 // TODO: make this algorithm shared with ByteArrayUuencodingStreamEncoder again 0083 bool ByteArrayXxencodingStreamEncoder::encodeDataToStream(QIODevice* device, 0084 const ByteArrayView* byteArrayView, 0085 const Okteta::AbstractByteArrayModel* byteArrayModel, 0086 const Okteta::AddressRange& range) 0087 { 0088 Q_UNUSED(byteArrayView); 0089 0090 const char header[] = "begin"; 0091 const char footer[] = "\n+\nend\n"; 0092 0093 bool success = true; 0094 0095 // encode 0096 QTextStream textStream(device); 0097 0098 // prepare 0099 InputByteIndex inputByteIndex = InputByteIndex::First; 0100 int inputGroupsPerLine = 0; 0101 unsigned char bitsFromLastByte; 0102 0103 // header 0104 textStream << header << " 644 " << mSettings.fileName.toLatin1(); 0105 0106 const int firstLineLength = qMin(range.width(), xxInputLineLength); 0107 if (firstLineLength > 0) { 0108 textStream << '\n'; 0109 textStream << xxmapByte(firstLineLength); 0110 } 0111 0112 for (Okteta::Address i = range.start(); i <= range.end(); ++i) { 0113 const Okteta::Byte byte = byteArrayModel->byte(i); 0114 0115 switch (inputByteIndex) 0116 { 0117 case InputByteIndex::First: 0118 // bits 7..2 0119 textStream << xxmapByte(byte >> 2); 0120 // bits 1..0 -> 5..4 for next 0121 bitsFromLastByte = (byte & 0x3) << 4; 0122 inputByteIndex = InputByteIndex::Second; 0123 break; 0124 case InputByteIndex::Second: 0125 // from last and bits 7..4 as 3..0 from this 0126 textStream << xxmapByte(bitsFromLastByte | byte >> 4); 0127 // bits 3..0 -> 5..2 for next 0128 bitsFromLastByte = (byte & 0xf) << 2; 0129 inputByteIndex = InputByteIndex::Third; 0130 break; 0131 case InputByteIndex::Third: 0132 // from last and bits 7..6 as 1..0 from this 0133 textStream << xxmapByte(bitsFromLastByte | byte >> 6); 0134 // bits 5..0 0135 textStream << xxmapByte(byte & 0x3F); 0136 inputByteIndex = InputByteIndex::First; 0137 ++inputGroupsPerLine; 0138 if (inputGroupsPerLine >= maxXxInputGroupsPerLine && i < range.end()) { 0139 const int remainsCount = range.end() - i; 0140 const int nextLineLength = qMin(remainsCount, xxInputLineLength); 0141 textStream << '\n'; 0142 textStream << xxmapByte(nextLineLength); 0143 inputGroupsPerLine = 0; 0144 } 0145 break; 0146 } 0147 } 0148 0149 const bool hasBitsLeft = (inputByteIndex != InputByteIndex::First); 0150 if (hasBitsLeft) { 0151 textStream << xxmapByte(bitsFromLastByte) 0152 << xxpadding(inputByteIndex); 0153 } 0154 // footer 0155 textStream << footer; 0156 0157 return success; 0158 } 0159 0160 } 0161 0162 #include "moc_bytearrayxxencodingstreamencoder.cpp"