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"