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: 2008 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 "bytearrayrowscolumntextrenderer.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 ByteArrayRowsColumnTextRenderer::ByteArrayRowsColumnTextRenderer(const Okteta::AbstractByteArrayModel* byteArrayModel,
0022                                                                  Okteta::Address offset,
0023                                                                  const Okteta::CoordRange& coordRange,
0024                                                                  int noOfBytesPerLine, int byteSpacingWidth, 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     , mLinePositions(new int[mNoOfBytesPerLine])
0038 {
0039     const int encodingWidth = (mVisibleCodings & 1) ? mValueCodec->encodingWidth() : 1;
0040     setWidths(encodingWidth, byteSpacingWidth, noOfGroupedBytes);
0041 }
0042 
0043 ByteArrayRowsColumnTextRenderer::~ByteArrayRowsColumnTextRenderer()
0044 {
0045     delete [] mLinePositions;
0046     delete mCharCodec;
0047     delete mValueCodec;
0048 }
0049 
0050 int ByteArrayRowsColumnTextRenderer::noOfSublinesNeeded() const
0051 {
0052     return (mVisibleCodings > 2) ? 2 : 1;
0053 }
0054 
0055 void ByteArrayRowsColumnTextRenderer::setWidths(int byteWidth, int byteSpacingWidth, int noOfGroupedBytes)
0056 {
0057     // TODO: remove this hack and make it more general
0058     if (byteSpacingWidth > 0) {
0059         byteSpacingWidth = DefaultTRByteSpacingWidth;
0060     }
0061 
0062     int spacingTrigger = noOfGroupedBytes - 1;
0063     if (spacingTrigger < 0) {
0064         spacingTrigger = mNoOfBytesPerLine; // ensures to never trigger the group spacing
0065 
0066     }
0067     int N = 0;
0068     int p = 0;
0069     int gs = 0;
0070     int* P = mLinePositions;
0071     for (; P < &mLinePositions[mNoOfBytesPerLine]; ++P, ++p, ++gs) {
0072         *P = N;
0073         N += byteWidth;
0074 
0075         // is there a space behind the actual byte (if it is not the last)?
0076         if (gs == spacingTrigger) {
0077             N += TRGroupSpacingWidth;
0078             gs = -1;
0079         } else {
0080             N += byteSpacingWidth;
0081         }
0082     }
0083 
0084     N -= (gs == 0) ? TRGroupSpacingWidth : byteSpacingWidth;
0085 
0086     mNoOfCharsPerLine = N;
0087 }
0088 
0089 void ByteArrayRowsColumnTextRenderer::renderFirstLine(QTextStream* stream, int lineIndex) const
0090 {
0091     mRenderLine = lineIndex;
0092     renderLine(stream, false);
0093 }
0094 
0095 void ByteArrayRowsColumnTextRenderer::renderNextLine(QTextStream* stream, bool isSubline) const
0096 {
0097     renderLine(stream, isSubline);
0098 }
0099 
0100 void ByteArrayRowsColumnTextRenderer::renderLine(QTextStream* stream, bool isSubline) const
0101 {
0102     const int lineOffset = mOffset;
0103 
0104     int p = 0;
0105     int pEnd = mNoOfBytesPerLine;
0106     // correct boundaries
0107     if (mRenderLine == mCoordRange.start().line()) {
0108         p = mCoordRange.start().pos();
0109     }
0110     if (mRenderLine == mCoordRange.end().line()) {
0111         pEnd = mCoordRange.end().pos() + 1;
0112     }
0113 
0114     uint e = 0;
0115     if (isSubline || mVisibleCodings == 2) {
0116         const QChar tabChar = QLatin1Char('\t');
0117         const QChar returnChar = QLatin1Char('\n');
0118 
0119         // draw individual chars
0120         for (; p < pEnd; ++p, ++mOffset) {
0121             // get next position
0122             const uint t = mLinePositions[p];
0123             // clear spacing
0124             *stream << whiteSpace(t - e);
0125 
0126             // print char
0127             const Okteta::Character byteChar = mCharCodec->decode(mByteArrayModel->byte(mOffset));
0128 
0129             const QChar streamChar = byteChar.isUndefined() ?      Okteta::Character(mUndefinedChar) :
0130                                      (!byteChar.isPrint()
0131                                       || byteChar == tabChar
0132                                       || byteChar == returnChar) ? Okteta::Character(mSubstituteChar) :
0133                                                                    byteChar;
0134             *stream << streamChar;
0135 
0136             e = t + 1;
0137         }
0138     } else {
0139         QString E;
0140         E.resize(mValueCodec->encodingWidth());
0141         // draw individual chars
0142         for (; p < pEnd; ++p, ++mOffset) {
0143             // get next position
0144             const uint t = mLinePositions[p];
0145             // clear spacing
0146             *stream << whiteSpace(t - e);
0147             mValueCodec->encode(&E, 0, mByteArrayModel->byte(mOffset));
0148             *stream << E;
0149             e = t + mValueCodec->encodingWidth();
0150         }
0151     }
0152 
0153     *stream << whiteSpace(mNoOfCharsPerLine - e);
0154 
0155     if (isSubline || mVisibleCodings < 3) {
0156         ++mRenderLine;
0157     } else {
0158         mOffset = lineOffset;
0159     }
0160 }
0161 
0162 }