File indexing completed on 2024-03-24 17:26:37

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