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 }