File indexing completed on 2024-04-14 05:45:46

0001 /*
0002     This file is part of the Okteta Core library, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2003, 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 "fixedsizebytearraymodel.hpp"
0010 
0011 // lib
0012 #include "arraychangemetricslist.hpp"
0013 #include <logging.hpp>
0014 // Std
0015 #include <cstring>
0016 
0017 namespace Okteta {
0018 
0019 FixedSizeByteArrayModel::FixedSizeByteArrayModel(Byte* data, int size, Byte fillUpByte, QObject* parent)
0020     : AbstractByteArrayModel(parent)
0021     , mData(data)
0022     , mSize(size)
0023     , mFillUpByte(fillUpByte)
0024     , mReadOnly(true)
0025     , mModified(false)
0026     , mAutoDelete(false)
0027 {
0028 }
0029 
0030 FixedSizeByteArrayModel::FixedSizeByteArrayModel(int size, Byte fillUpByte, QObject* parent)
0031     : AbstractByteArrayModel(parent)
0032     , mData(new Byte[size])
0033     , mSize(size)
0034     , mFillUpByte(fillUpByte)
0035     , mReadOnly(false)
0036     , mModified(false)
0037     , mAutoDelete(true)
0038 {
0039     reset(0, size);
0040 }
0041 
0042 FixedSizeByteArrayModel::~FixedSizeByteArrayModel()
0043 {
0044     if (mAutoDelete) {
0045         delete [] mData;
0046     }
0047 }
0048 
0049 void FixedSizeByteArrayModel::setByte(Address offset, Byte byte)
0050 {
0051     const bool wasModifiedBefore = mModified;
0052 
0053     mData[offset] = byte;
0054     mModified = true;
0055 
0056     Q_EMIT contentsChanged(ArrayChangeMetricsList::oneReplacement(offset, 1, 1));
0057     if (!wasModifiedBefore) {
0058         Q_EMIT modifiedChanged(true);
0059     }
0060 }
0061 
0062 Size FixedSizeByteArrayModel::insert(Address offset, const Byte* insertData, int insertLength)
0063 {
0064     // check all parameters
0065     if (offset >= mSize || insertLength == 0) {
0066         return 0;
0067     }
0068 
0069     const bool wasModifiedBefore = mModified;
0070 
0071     if (offset + insertLength > mSize) {
0072         insertLength = mSize - offset;
0073     }
0074 
0075     const Address behindInsertOffset = offset + insertLength;
0076     // fmove right data behind the input range
0077     memmove(&mData[behindInsertOffset], &mData[offset], mSize - behindInsertOffset);
0078     // insert input
0079     memcpy(&mData[offset], insertData, insertLength);
0080 
0081     mModified = true;
0082 
0083     Q_EMIT contentsChanged(ArrayChangeMetricsList::oneReplacement(offset, 0, insertLength));
0084     // Q_EMIT contentsReplaced( offset, , 0 ); TODO: how to signal the removed data?
0085     if (!wasModifiedBefore) {
0086         Q_EMIT modifiedChanged(true);
0087     }
0088 
0089     return insertLength;
0090 }
0091 
0092 Size FixedSizeByteArrayModel::remove(const AddressRange& _removeRange)
0093 {
0094     AddressRange removeRange(_removeRange);
0095     if (removeRange.start() >= mSize || removeRange.width() == 0) {
0096         return 0;
0097     }
0098 
0099     const bool wasModifiedBefore = mModified;
0100 
0101     removeRange.restrictEndTo(mSize - 1);
0102 
0103     const Size removeLength = removeRange.width();
0104     const Address behindRemoveOffset = removeRange.nextBehindEnd();
0105     // fmove right data behind the input range
0106     memmove(&mData[removeRange.start()], &mData[behindRemoveOffset], mSize - behindRemoveOffset);
0107     // clear freed space
0108     reset(mSize - removeLength, removeLength);
0109 
0110     mModified = true;
0111 
0112     Q_EMIT contentsChanged(ArrayChangeMetricsList::oneReplacement(removeRange.start(), removeRange.width(), 0));
0113     // Q_EMIT contentsReplaced( offset, 0,  ); TODO: how to signal the inserted data?
0114     if (!wasModifiedBefore) {
0115         Q_EMIT modifiedChanged(true);
0116     }
0117 
0118     return removeLength;
0119 }
0120 
0121 Size FixedSizeByteArrayModel::replace(const AddressRange& _removeRange, const Byte* insertData, int insertLength)
0122 {
0123     AddressRange removeRange(_removeRange);
0124     // check all parameters
0125     if (removeRange.startsBehind(mSize - 1) || (removeRange.width() == 0 && insertLength == 0)) {
0126         return 0;
0127     }
0128 
0129     const bool wasModifiedBefore = mModified;
0130 
0131     removeRange.restrictEndTo(mSize - 1);
0132     if (removeRange.start() + insertLength > mSize) {
0133         insertLength = mSize - removeRange.start();
0134     }
0135 
0136     const Size sizeDiff = insertLength - removeRange.width();
0137 
0138     // is input longer than removed?
0139     if (sizeDiff > 0) {
0140         const Address behindInsertOffset = removeRange.start() + insertLength;
0141         // fmove right data behind the input range
0142         memmove(&mData[behindInsertOffset], &mData[removeRange.nextBehindEnd()], mSize - behindInsertOffset);
0143     }
0144     // is input smaller than removed?
0145     else if (sizeDiff < 0) {
0146         const Address behindRemoveOffset = removeRange.nextBehindEnd();
0147         // fmove right data behind the input range
0148         memmove(&mData[removeRange.start() + insertLength], &mData[behindRemoveOffset], mSize - behindRemoveOffset);
0149         // clear freed space
0150         reset(mSize + sizeDiff, -sizeDiff);
0151     }
0152     // insert input
0153     memcpy(&mData[removeRange.start()], insertData, insertLength);
0154 
0155     mModified = true;
0156 
0157     Q_EMIT contentsChanged(ArrayChangeMetricsList::oneReplacement(removeRange.start(), removeRange.width(), insertLength));
0158     // Q_EMIT contentsReplaced( offset, 0,  ); TODO: how to signal the changed data at the end?
0159     if (!wasModifiedBefore) {
0160         Q_EMIT modifiedChanged(true);
0161     }
0162 
0163     return insertLength;
0164 }
0165 
0166 bool FixedSizeByteArrayModel::swap(Address firstStart, const AddressRange& _secondRange)
0167 {
0168     AddressRange secondRange(_secondRange);
0169     // check all parameters
0170     if (secondRange.start() >= mSize || secondRange.width() == 0
0171         || firstStart > mSize || secondRange.start() == firstStart) {
0172         return false;
0173     }
0174 
0175     const bool wasModifiedBefore = mModified;
0176 
0177     secondRange.restrictEndTo(mSize - 1);
0178     const bool toRight = firstStart > secondRange.start();
0179     const Size movedLength = secondRange.width();
0180     const Size displacedLength = toRight ?  firstStart - secondRange.end() - 1 : secondRange.start() - firstStart;
0181 
0182     // find out section that is smaller
0183     Size smallPartLength, largePartLength, smallPartStart, largePartStart, smallPartDest, largePartDest;
0184     // moving part is smaller?
0185     if (movedLength < displacedLength) {
0186         smallPartStart = secondRange.start();
0187         smallPartLength = movedLength;
0188         largePartLength = displacedLength;
0189         // moving part moves right?
0190         if (toRight) {
0191             smallPartDest = firstStart - movedLength;
0192             largePartStart = secondRange.nextBehindEnd();
0193             largePartDest = secondRange.start();
0194         } else {
0195             smallPartDest = firstStart;
0196             largePartStart = firstStart;
0197             largePartDest = firstStart + movedLength;
0198         }
0199     } else {
0200         largePartStart = secondRange.start();
0201         largePartLength = movedLength;
0202         smallPartLength = displacedLength;
0203         // moving part moves right?
0204         if (toRight) {
0205             largePartDest = firstStart - movedLength;
0206             smallPartStart = secondRange.nextBehindEnd();
0207             smallPartDest = secondRange.start();
0208         } else {
0209             largePartDest = firstStart;
0210             smallPartStart = firstStart;
0211             smallPartDest = firstStart + movedLength;
0212         }
0213     }
0214 
0215     // copy smaller part to tempbuffer
0216     auto* tempBuffer = new Byte[smallPartLength];
0217     memcpy(tempBuffer, &mData[smallPartStart], smallPartLength);
0218 
0219     // move the larger part
0220     memmove(&mData[largePartDest], &mData[largePartStart], largePartLength);
0221 
0222     // copy smaller part to its new dest
0223     memcpy(&mData[smallPartDest], tempBuffer, smallPartLength);
0224     delete [] tempBuffer;
0225 
0226     mModified = true;
0227 
0228     Q_EMIT contentsChanged(ArrayChangeMetricsList::oneSwapping(firstStart, secondRange.start(), secondRange.width()));
0229     if (!wasModifiedBefore) {
0230         Q_EMIT modifiedChanged(true);
0231     }
0232 
0233     return true;
0234 }
0235 
0236 Size FixedSizeByteArrayModel::fill(Byte fillByte, Address offset, Size fillLength)
0237 {
0238     // nothing to fill
0239     if (offset >= mSize) {
0240         return 0;
0241     }
0242 
0243     const bool wasModifiedBefore = mModified;
0244 
0245     const Size lengthToEnd = mSize - offset;
0246 
0247     if (fillLength < 0 || fillLength > lengthToEnd) {
0248         fillLength = lengthToEnd;
0249     }
0250 
0251     if (fillLength == 0) {
0252         return 0;
0253     }
0254 
0255     memset(&mData[offset], fillByte, fillLength);
0256     mModified = true;
0257 
0258     Q_EMIT contentsChanged(ArrayChangeMetricsList::oneReplacement(offset, fillLength, fillLength));
0259     if (!wasModifiedBefore) {
0260         Q_EMIT modifiedChanged(true);
0261     }
0262 
0263     return fillLength;
0264 }
0265 
0266 int FixedSizeByteArrayModel::compare(const AbstractByteArrayModel& other, const AddressRange& _otherRange, Address offset)
0267 {
0268     AddressRange otherRange(_otherRange);
0269     // qCDebug(LOG_OKTETA_CORE) << QString("offset: %1, otherRange: (%3/%4)" ).arg(offset).arg(otherRange.start()).arg(otherRange.end())
0270     //    << endl;
0271     // test other values
0272     if (otherRange.startsBehind(other.size() - 1)) {
0273         return 1;
0274     }
0275 
0276     // check own values
0277     if (offset >= mSize) {
0278         return -1;
0279     }
0280 
0281     int valueByLength = 0; // default: equal
0282 
0283     AddressRange range = AddressRange::fromWidth(offset, otherRange.width());
0284     Address lastOffset = other.size() - 1;
0285     //
0286     if (otherRange.endsBehind(lastOffset)) {
0287         // make shorter
0288         otherRange.setEnd(lastOffset);
0289         if (otherRange.width() < range.width()) {
0290             valueByLength = 1;
0291         }
0292     }
0293     lastOffset = mSize - 1;
0294     if (range.endsBehind(lastOffset)) {
0295         // make shorter
0296         range.setEnd(lastOffset);
0297         if (otherRange.width() > range.width()) {
0298             valueByLength = -1;
0299         }
0300     }
0301     // qCDebug(LOG_OKTETA_CORE)
0302     //    << QString( "range: (%1/%2), otherRange: (%3/%4)" ).arg(range.start()).arg(range.end()).arg(otherRange.start()).arg(otherRange.end())
0303     //    << endl;
0304     const Address rangeEnd = range.end();
0305     Address oi = otherRange.start();
0306     for (Address i = range.start(); i <= rangeEnd; ++i, ++oi) {
0307         Byte OD = other.byte(oi);
0308         Byte data = mData[i];
0309         // qCDebug(LOG_OKTETA_CORE) << QString("%1==%2").arg((int)data).arg((int)OD) ;
0310         if (OD == data) {
0311             continue;
0312         }
0313         return (OD < data) ? 1 : -1;
0314     }
0315 
0316     return valueByLength;
0317 }
0318 
0319 void FixedSizeByteArrayModel::reset(unsigned int offset, unsigned int length)
0320 {
0321     memset(&mData[offset], mFillUpByte, length);
0322 }
0323 
0324 }
0325 
0326 #include "moc_fixedsizebytearraymodel.cpp"