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"