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: 2023 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 "bytearrayrowscolumnhtmlrenderer.hpp"
0010 
0011 // Okteta core
0012 #include <Okteta/ValueCodec>
0013 #include <Okteta/CharCodec>
0014 #include <Okteta/Character>
0015 #include <Okteta/AbstractByteArrayModel>
0016 // Qt
0017 #include <QTextStream>
0018 
0019 namespace Kasten {
0020 
0021 ByteArrayRowsColumnHtmlRenderer::ByteArrayRowsColumnHtmlRenderer(const Okteta::AbstractByteArrayModel* byteArrayModel,
0022                                                                  Okteta::Address offset,
0023                                                                  const Okteta::CoordRange& coordRange,
0024                                                                  int noOfBytesPerLine, int noOfGroupedBytes,
0025                                                                  int visibleCodings,
0026                                                                  Okteta::ValueCoding valueCoding,
0027                                                                  const QString& charCodecName, QChar substituteChar, QChar undefinedChar)
0028     : mByteArrayModel(byteArrayModel)
0029     , mCoordRange(coordRange)
0030     , mNoOfBytesPerLine(noOfBytesPerLine)
0031     , mVisibleCodings(visibleCodings)
0032     , mValueCodec(Okteta::ValueCodec::createCodec(valueCoding))
0033     , mCharCodec(Okteta::CharCodec::createCodec(charCodecName))
0034     , mSubstituteChar(substituteChar)
0035     , mUndefinedChar(undefinedChar)
0036     , mOffset(offset)
0037 {
0038     Q_UNUSED(noOfGroupedBytes);
0039 }
0040 
0041 ByteArrayRowsColumnHtmlRenderer::~ByteArrayRowsColumnHtmlRenderer() = default;
0042 
0043 int ByteArrayRowsColumnHtmlRenderer::noOfSublinesNeeded() const
0044 {
0045     return (mVisibleCodings > 2) ? 2 : 1;
0046 }
0047 
0048 void ByteArrayRowsColumnHtmlRenderer::renderFirstLine(QTextStream* stream, int lineIndex) const
0049 {
0050     mRenderLine = lineIndex;
0051     renderLine(stream, false);
0052 }
0053 
0054 void ByteArrayRowsColumnHtmlRenderer::renderNextLine(QTextStream* stream, bool isSubline) const
0055 {
0056     renderLine(stream, isSubline);
0057 }
0058 
0059 void ByteArrayRowsColumnHtmlRenderer::renderLine(QTextStream* stream, bool isSubline) const
0060 {
0061     const int lineOffset = mOffset;
0062 
0063     int p = 0;
0064     int pEnd = mNoOfBytesPerLine;
0065     // correct boundaries
0066     if (mRenderLine == mCoordRange.start().line()) {
0067         p = mCoordRange.start().pos();
0068     }
0069     if (mRenderLine == mCoordRange.end().line()) {
0070         pEnd = mCoordRange.end().pos() + 1;
0071     }
0072     const bool needsFilledEmptyCells =
0073         (mCoordRange.lines() == 1) ? ((0 < p) || (pEnd < mNoOfBytesPerLine)) :
0074         (mCoordRange.lines() == 2) ? (mCoordRange.end().pos() + 1 < mCoordRange.start().pos() ) :
0075         /* eefault */                false;
0076     const unsigned int codingWidth = needsFilledEmptyCells ? mValueCodec->encodingWidth() : 0;
0077 
0078     *stream << emptyCells(p, codingWidth);
0079 
0080     if (isSubline || mVisibleCodings == 2) {
0081         const QChar tabChar = QLatin1Char('\t');
0082         const QChar returnChar = QLatin1Char('\n');
0083 
0084         // render individual chars
0085         for (; p < pEnd; ++p, ++mOffset) {
0086             const Okteta::Character byteChar = mCharCodec->decode(mByteArrayModel->byte(mOffset));
0087 
0088             const QChar streamChar = byteChar.isUndefined() ?      Okteta::Character(mUndefinedChar) :
0089                                      (!byteChar.isPrint()
0090                                       || byteChar == tabChar
0091                                       || byteChar == returnChar) ? Okteta::Character(mSubstituteChar) :
0092                                                                    byteChar;
0093             *stream << "<td><tt>" << htmlEscaped(streamChar) << "</tt></td>";
0094         }
0095     } else {
0096         QString E;
0097         E.resize(mValueCodec->encodingWidth());
0098         // render individual values
0099         for (; p < pEnd; ++p, ++mOffset) {
0100             mValueCodec->encode(&E, 0, mByteArrayModel->byte(mOffset));
0101             *stream << "<td><tt>" << E.toHtmlEscaped() << "</tt></td>";
0102         }
0103     }
0104 
0105     *stream << emptyCells(mNoOfBytesPerLine - p, codingWidth);
0106 
0107     if (isSubline || mVisibleCodings < 3) {
0108         ++mRenderLine;
0109     } else {
0110         mOffset = lineOffset;
0111     }
0112 }
0113 
0114 }