File indexing completed on 2024-04-14 15:52:44
0001 /* 0002 This file is part of the Okteta Core library, made within the KDE community. 0003 0004 SPDX-FileCopyrightText: 2003, 2007, 2009 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 "bytearraymodel_p.hpp" 0010 0011 // Std 0012 #include <cstring> 0013 #include <cstdlib> 0014 0015 static constexpr int minChunkSize = 512; 0016 static constexpr int maxChunkSize = 1024 * 10; // TODO: get max. memory page size 0017 0018 // TODO: think about realloc & Co. 0019 0020 namespace Okteta { 0021 0022 ByteArrayModelPrivate::ByteArrayModelPrivate(ByteArrayModel* parent, 0023 Byte* data, int size, int rawSize, bool keepsMemory) 0024 : AbstractByteArrayModelPrivate(parent) 0025 , mData(data) 0026 , mSize(size) 0027 , mRawSize(rawSize < size ? size : rawSize) 0028 , mKeepsMemory(keepsMemory) 0029 , mAutoDelete(false) 0030 , mReadOnly(true) 0031 , mModified(false) 0032 { 0033 } 0034 0035 ByteArrayModelPrivate::ByteArrayModelPrivate(ByteArrayModel* parent, 0036 const Byte* data, int size) 0037 : AbstractByteArrayModelPrivate(parent) 0038 , mData(const_cast<Byte*>(data)) 0039 , mSize(size) 0040 , mRawSize(size) 0041 , mKeepsMemory(true) 0042 , mAutoDelete(false) 0043 , mReadOnly(true) 0044 , mModified(false) 0045 { 0046 } 0047 0048 ByteArrayModelPrivate::ByteArrayModelPrivate(ByteArrayModel* parent, 0049 int size, int maxSize) 0050 : AbstractByteArrayModelPrivate(parent) 0051 , mData((size > 0) ? new Byte[size] : nullptr) 0052 , mSize(size) 0053 , mRawSize(size) 0054 , mMaxSize(maxSize) 0055 , mKeepsMemory(false) 0056 , mAutoDelete(true) 0057 , mReadOnly(false) 0058 , mModified(false) 0059 { 0060 } 0061 0062 void ByteArrayModelPrivate::setData(Byte* data, int size, int rawSize, bool keepMemory) 0063 { 0064 Q_Q(ByteArrayModel); 0065 0066 // use delete [], since usually mData should be allocated by calling new Byte[n] 0067 if (mAutoDelete) { 0068 delete [] mData; 0069 } 0070 const int oldSize = mSize; 0071 0072 mData = data; 0073 mSize = size; 0074 mRawSize = (rawSize < size) ? size : rawSize; 0075 if (mMaxSize != -1 && mMaxSize < size) { 0076 mMaxSize = size; 0077 } 0078 mKeepsMemory = keepMemory; 0079 0080 mModified = false; 0081 emit q->contentsChanged(ArrayChangeMetricsList::oneReplacement(0, oldSize, size)); 0082 emit q->modifiedChanged(false); 0083 } 0084 0085 Size ByteArrayModelPrivate::insert(Address offset, const Byte* insertData, int insertLength) 0086 { 0087 Q_Q(ByteArrayModel); 0088 0089 if (mReadOnly) { 0090 return 0; 0091 } 0092 // check all parameters 0093 if (insertLength == 0) { 0094 return 0; 0095 } 0096 0097 const bool wasModifiedBefore = mModified; 0098 0099 // correct for appending 0100 if (offset > mSize) { 0101 offset = mSize; 0102 } 0103 0104 insertLength = addSize(insertLength, offset, true); 0105 0106 // copy new data to its place 0107 memcpy(&mData[offset], insertData, insertLength); 0108 0109 const bool bookmarksModified = m_bookmarks.adjustToReplaced(offset, 0, insertLength); 0110 mModified = true; 0111 0112 emit q->contentsChanged(ArrayChangeMetricsList::oneReplacement(offset, 0, insertLength)); 0113 if (bookmarksModified) { 0114 emit q->bookmarksModified(true); 0115 } 0116 if (!wasModifiedBefore) { 0117 emit q->modifiedChanged(true); 0118 } 0119 0120 return insertLength; 0121 } 0122 0123 Size ByteArrayModelPrivate::remove(const AddressRange& _removeRange) 0124 { 0125 Q_Q(ByteArrayModel); 0126 0127 if (mReadOnly) { 0128 return 0; 0129 } 0130 0131 AddressRange removeRange(_removeRange); 0132 if (removeRange.startsBehind(mSize - 1) || removeRange.width() == 0) { 0133 return 0; 0134 } 0135 0136 const bool wasModifiedBefore = mModified; 0137 0138 removeRange.restrictEndTo(mSize - 1); 0139 0140 const Address behindRemovePos = removeRange.nextBehindEnd(); 0141 // move right data behind the input range 0142 memmove(&mData[removeRange.start()], &mData[behindRemovePos], mSize - behindRemovePos); 0143 0144 // set new values 0145 mSize -= removeRange.width(); 0146 0147 const bool bookmarksModified = m_bookmarks.adjustToReplaced(removeRange.start(), removeRange.width(), 0); 0148 mModified = true; 0149 0150 emit q->contentsChanged(ArrayChangeMetricsList::oneReplacement(removeRange.start(), removeRange.width(), 0)); 0151 if (bookmarksModified) { 0152 emit q->bookmarksModified(true); 0153 } 0154 if (!wasModifiedBefore) { 0155 emit q->modifiedChanged(true); 0156 } 0157 0158 return removeRange.width(); 0159 } 0160 0161 Size ByteArrayModelPrivate::replace(const AddressRange& _removeRange, const Byte* insertData, int insertLength) 0162 { 0163 Q_Q(ByteArrayModel); 0164 0165 if (mReadOnly) { 0166 return 0; 0167 } 0168 0169 AddressRange removeRange(_removeRange); 0170 // check all parameters 0171 if (removeRange.start() >= mSize || (removeRange.width() == 0 && insertLength == 0)) { 0172 return 0; 0173 } 0174 0175 const bool wasModifiedBefore = mModified; 0176 0177 removeRange.restrictEndTo(mSize - 1); 0178 0179 const Size sizeDiff = insertLength - removeRange.width(); 0180 int newSize = mSize + sizeDiff; 0181 // check if buffer does not get to big TODO: make algo simplier and less if else 0182 if (mMaxSize != -1 && newSize > mMaxSize) { 0183 if (mSize == mMaxSize) { 0184 return 0; 0185 } 0186 insertLength -= newSize - mMaxSize; 0187 newSize = mMaxSize; 0188 } else if (mKeepsMemory && newSize > mRawSize) { 0189 if (mSize == mRawSize) { 0190 return 0; 0191 } 0192 insertLength -= newSize - mRawSize; 0193 newSize = mRawSize; 0194 } 0195 0196 const Address behindInsertPos = removeRange.start() + insertLength; 0197 const Address behindRemovePos = removeRange.nextBehindEnd(); 0198 0199 // raw array not big enough? 0200 if (mRawSize < newSize) { 0201 // create new buffer 0202 auto* newData = new Byte[newSize]; 0203 if (!newData) { 0204 return 0; 0205 } 0206 0207 // move old data to its (new) places 0208 memcpy(newData, mData, removeRange.start()); 0209 memcpy(&newData[behindInsertPos], &mData[behindRemovePos], mSize - behindRemovePos); 0210 0211 // remove old 0212 delete [] mData; 0213 // set new values 0214 mData = newData; 0215 mRawSize = newSize; 0216 } else { 0217 // move old data to its (new) places 0218 memmove(&mData[behindInsertPos], &mData[behindRemovePos], mSize - behindRemovePos); 0219 } 0220 0221 // copy new data to its place 0222 memcpy(&mData[removeRange.start()], insertData, insertLength); 0223 0224 // set new values 0225 mSize = newSize; 0226 0227 const bool bookmarksModified = m_bookmarks.adjustToReplaced(removeRange.start(), removeRange.width(), insertLength); 0228 mModified = true; 0229 0230 emit q->contentsChanged( 0231 ArrayChangeMetricsList::oneReplacement(removeRange.start(), removeRange.width(), insertLength)); 0232 if (bookmarksModified) { 0233 emit q->bookmarksModified(true); 0234 } 0235 if (!wasModifiedBefore) { 0236 emit q->modifiedChanged(true); 0237 } 0238 return insertLength; 0239 } 0240 0241 bool ByteArrayModelPrivate::swap(Address firstStart, const AddressRange& _secondRange) 0242 { 0243 Q_Q(ByteArrayModel); 0244 0245 if (mReadOnly) { 0246 return false; 0247 } 0248 0249 AddressRange secondRange(_secondRange); 0250 // check all parameters 0251 if (secondRange.start() >= mSize || secondRange.width() == 0 0252 || firstStart > mSize || secondRange.start() == firstStart) { 0253 return false; 0254 } 0255 0256 const bool wasModifiedBefore = mModified; 0257 0258 secondRange.restrictEndTo(mSize - 1); 0259 const bool toRight = firstStart > secondRange.start(); 0260 const Size movedLength = secondRange.width(); 0261 const Size displacedLength = toRight ? firstStart - secondRange.end() - 1 : secondRange.start() - firstStart; 0262 0263 // find out section that is smaller 0264 Size smallPartLength, largePartLength, smallPartStart, largePartStart, smallPartDest, largePartDest; 0265 // moving part is smaller? 0266 if (movedLength < displacedLength) { 0267 smallPartStart = secondRange.start(); 0268 smallPartLength = movedLength; 0269 largePartLength = displacedLength; 0270 // moving part moves right? 0271 if (toRight) { 0272 smallPartDest = firstStart - movedLength; 0273 largePartStart = secondRange.nextBehindEnd(); 0274 largePartDest = secondRange.start(); 0275 } else { 0276 smallPartDest = firstStart; 0277 largePartStart = firstStart; 0278 largePartDest = firstStart + movedLength; 0279 } 0280 } else { 0281 largePartStart = secondRange.start(); 0282 largePartLength = movedLength; 0283 smallPartLength = displacedLength; 0284 // moving part moves right? 0285 if (toRight) { 0286 largePartDest = firstStart - movedLength; 0287 smallPartStart = secondRange.nextBehindEnd(); 0288 smallPartDest = secondRange.start(); 0289 } else { 0290 largePartDest = firstStart; 0291 smallPartStart = firstStart; 0292 smallPartDest = firstStart + movedLength; 0293 } 0294 } 0295 0296 // copy smaller part to tempbuffer 0297 auto* temp = new Byte[smallPartLength]; 0298 memcpy(temp, &mData[smallPartStart], smallPartLength); 0299 0300 // move the larger part 0301 memmove(&mData[largePartDest], &mData[largePartStart], largePartLength); 0302 0303 // copy smaller part to its new dest 0304 memcpy(&mData[smallPartDest], temp, smallPartLength); 0305 delete [] temp; 0306 0307 const bool bookmarksModified = toRight ? 0308 m_bookmarks.adjustToSwapped(secondRange.start(), secondRange.nextBehindEnd(), firstStart - secondRange.end() - 1) : 0309 m_bookmarks.adjustToSwapped(firstStart, secondRange.start(), secondRange.width()); 0310 mModified = true; 0311 0312 emit q->contentsChanged( 0313 ArrayChangeMetricsList::oneSwapping(firstStart, secondRange.start(), secondRange.width())); 0314 if (bookmarksModified) { 0315 emit q->bookmarksModified(true); 0316 } 0317 if (!wasModifiedBefore) { 0318 emit q->modifiedChanged(true); 0319 } 0320 return true; 0321 } 0322 0323 Size ByteArrayModelPrivate::fill(Byte fillByte, Address offset, Size fillLength) 0324 { 0325 Q_Q(ByteArrayModel); 0326 0327 if (mReadOnly) { 0328 return 0; 0329 } 0330 0331 // nothing to fill 0332 if ((offset >= mSize) || (fillLength == 0)) { 0333 return 0; 0334 } 0335 0336 const bool wasModifiedBefore = mModified; 0337 0338 const Size lengthToEnd = mSize - offset; 0339 0340 if (fillLength < 0) { 0341 fillLength = lengthToEnd; 0342 } 0343 0344 const bool isToFillBehindEnd = (fillLength > lengthToEnd); 0345 const Size replacedLength = (isToFillBehindEnd ? lengthToEnd : fillLength); 0346 0347 if (isToFillBehindEnd) { 0348 Size sizeToAdd = fillLength - lengthToEnd; 0349 sizeToAdd = addSize(sizeToAdd, offset, false); 0350 fillLength = lengthToEnd + sizeToAdd; 0351 } 0352 // nothing to fill 0353 if (fillLength == 0) { 0354 return 0; 0355 } 0356 0357 memset(&mData[offset], fillByte, fillLength); 0358 mModified = true; 0359 0360 emit q->contentsChanged(ArrayChangeMetricsList::oneReplacement(offset, replacedLength, fillLength)); 0361 if (!wasModifiedBefore) { 0362 emit q->modifiedChanged(true); 0363 } 0364 return fillLength; 0365 } 0366 0367 int ByteArrayModelPrivate::addSize(int addSize, int splitPosition, bool saveUpperPart) 0368 { 0369 if (mReadOnly) { 0370 return 0; 0371 } 0372 0373 int newSize = mSize + addSize; 0374 // check if buffer does not get too big 0375 if (mMaxSize != -1 && newSize > mMaxSize) { 0376 if (mSize == mMaxSize) { 0377 return 0; 0378 } 0379 newSize = mMaxSize; 0380 addSize = newSize - mSize; 0381 } else if (mKeepsMemory && newSize > mRawSize) { 0382 if (mSize == mRawSize) { 0383 return 0; 0384 } 0385 newSize = mRawSize; 0386 addSize = newSize - mSize; 0387 } 0388 0389 const int BehindSplitPos = splitPosition + addSize; 0390 // raw array not big enough? 0391 if (mRawSize < newSize) { 0392 // get new raw size 0393 int chunkSize = minChunkSize; 0394 // find chunk size where newsize fits into 0395 while (chunkSize < newSize) { 0396 chunkSize <<= 1; 0397 } 0398 // limit to max size 0399 if (chunkSize > maxChunkSize) { 0400 chunkSize = maxChunkSize; 0401 } 0402 // find add size 0403 int NewRawSize = chunkSize; 0404 while (NewRawSize < newSize) { 0405 NewRawSize += chunkSize; 0406 } 0407 // create new buffer 0408 auto* newData = new Byte[NewRawSize]; 0409 0410 // move old data to its (new) places 0411 memcpy(newData, mData, splitPosition); 0412 if (saveUpperPart) { 0413 memcpy(&newData[BehindSplitPos], &mData[splitPosition], mSize - splitPosition); 0414 } 0415 0416 // remove old 0417 delete [] mData; 0418 // set new values 0419 mData = newData; 0420 mRawSize = NewRawSize; 0421 } 0422 // old buffer kept 0423 else { 0424 if (saveUpperPart) { 0425 // move old data to its (new) places 0426 memmove(&mData[BehindSplitPos], &mData[splitPosition], mSize - splitPosition); 0427 } 0428 } 0429 0430 // set new values 0431 mSize = newSize; 0432 0433 return addSize; 0434 } 0435 0436 }