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"