File indexing completed on 2025-03-09 05:20:43
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 "bytearraybase85streamencoder.hpp" 0010 0011 // Okteta core 0012 #include <Okteta/AbstractByteArrayModel> 0013 // KF 0014 #include <KLocalizedString> 0015 // Qt 0016 #include <QTextStream> 0017 0018 namespace Kasten { 0019 0020 static inline void streamEncoded(QTextStream& textStream, int& outputBytesPerLine, 0021 quint32 tuple, int inputByteCount) 0022 { 0023 // radix85 values, most significant first 0024 char data[5]; 0025 0026 for (int i = 4; i >= 0; --i) { 0027 // TODO: find an efficient bit manipulating algorithm 0028 data[i] = tuple % 85; 0029 tuple /= 85; 0030 } 0031 0032 // output inputByteCount+1 from radix85 values 0033 for (int i = 0; i <= inputByteCount; ++i) { 0034 textStream << (char)(data[i] + 33); 0035 ++outputBytesPerLine; 0036 if (outputBytesPerLine >= ByteArrayBase85StreamEncoder::maxOutputBytesPerLine) { 0037 textStream << '\n'; 0038 outputBytesPerLine = 0; 0039 } 0040 } 0041 } 0042 0043 // TODO: for now this is just the Adobe/Ascii85 implementation, so present as that 0044 // later also add btoa with different version, e.g. 4.2 added a "y" for 4 spaces 0045 ByteArrayBase85StreamEncoder::ByteArrayBase85StreamEncoder() 0046 : AbstractByteArrayStreamEncoder(i18nc("name of the encoding target", "Ascii85"), QStringLiteral("text/x-ascii85")) 0047 {} 0048 0049 ByteArrayBase85StreamEncoder::~ByteArrayBase85StreamEncoder() = default; 0050 0051 bool ByteArrayBase85StreamEncoder::encodeDataToStream(QIODevice* device, 0052 const ByteArrayView* byteArrayView, 0053 const Okteta::AbstractByteArrayModel* byteArrayModel, 0054 const Okteta::AddressRange& range) 0055 { 0056 Q_UNUSED(byteArrayView); 0057 0058 bool success = true; 0059 0060 // encode 0061 QTextStream textStream(device); 0062 0063 // prepare 0064 InputByteIndex inputByteIndex = InputByteIndex::First; 0065 quint32 tuple = 0; 0066 0067 // header 0068 int outputBytesPerLine = 2; 0069 textStream << "<~"; 0070 0071 for (Okteta::Address i = range.start(); i <= range.end(); ++i) { 0072 const Okteta::Byte byte = byteArrayModel->byte(i); 0073 0074 switch (inputByteIndex) 0075 { 0076 case InputByteIndex::First: 0077 tuple |= (byte << 24); 0078 inputByteIndex = InputByteIndex::Second; 0079 break; 0080 case InputByteIndex::Second: 0081 tuple |= (byte << 16); 0082 inputByteIndex = InputByteIndex::Third; 0083 break; 0084 case InputByteIndex::Third: 0085 tuple |= (byte << 8); 0086 inputByteIndex = InputByteIndex::Fourth; 0087 break; 0088 case InputByteIndex::Fourth: 0089 tuple |= byte; 0090 if (tuple == 0) { 0091 textStream << 'z'; 0092 ++outputBytesPerLine; 0093 if (outputBytesPerLine >= maxOutputBytesPerLine) { 0094 textStream << '\n'; 0095 outputBytesPerLine = 0; 0096 } 0097 } else { 0098 streamEncoded(textStream, outputBytesPerLine, tuple, static_cast<int>(inputByteIndex) + 1); 0099 } 0100 tuple = 0; 0101 inputByteIndex = InputByteIndex::First; 0102 break; 0103 } 0104 } 0105 0106 const bool hasBitsLeft = (inputByteIndex != InputByteIndex::First); 0107 if (hasBitsLeft) { 0108 streamEncoded(textStream, outputBytesPerLine, tuple, static_cast<int>(inputByteIndex)); 0109 } 0110 0111 // footer 0112 if (outputBytesPerLine + 2 > maxOutputBytesPerLine) { 0113 textStream << '\n'; 0114 } 0115 textStream << "~>\n"; 0116 0117 return success; 0118 } 0119 0120 } 0121 0122 #include "moc_bytearraybase85streamencoder.cpp"