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 }