Close #6435:
* fix problem in TextGapBuffer which could lead to data loss at end of buffer when deleting large chunks of text git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37987 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -59,10 +59,10 @@ TextGapBuffer::InsertText(const char* inText, int32 inNumItems, int32 inAtIndex)
|
|||||||
inAtIndex = (inAtIndex < 0) ? 0 : inAtIndex;
|
inAtIndex = (inAtIndex < 0) ? 0 : inAtIndex;
|
||||||
|
|
||||||
if (inAtIndex != fGapIndex)
|
if (inAtIndex != fGapIndex)
|
||||||
MoveGapTo(inAtIndex);
|
_MoveGapTo(inAtIndex);
|
||||||
|
|
||||||
if (fGapCount < inNumItems)
|
if (fGapCount < inNumItems)
|
||||||
SizeGapTo(inNumItems + kTextGapBufferBlockSize);
|
_EnlargeGapTo(inNumItems + kTextGapBufferBlockSize);
|
||||||
|
|
||||||
memcpy(fBuffer + fGapIndex, inText, inNumItems);
|
memcpy(fBuffer + fGapIndex, inText, inNumItems);
|
||||||
|
|
||||||
@@ -95,10 +95,10 @@ TextGapBuffer::InsertText(BFile* file, int32 fileOffset, int32 inNumItems,
|
|||||||
inAtIndex = (inAtIndex < 0) ? 0 : inAtIndex;
|
inAtIndex = (inAtIndex < 0) ? 0 : inAtIndex;
|
||||||
|
|
||||||
if (inAtIndex != fGapIndex)
|
if (inAtIndex != fGapIndex)
|
||||||
MoveGapTo(inAtIndex);
|
_MoveGapTo(inAtIndex);
|
||||||
|
|
||||||
if (fGapCount < inNumItems)
|
if (fGapCount < inNumItems)
|
||||||
SizeGapTo(inNumItems + kTextGapBufferBlockSize);
|
_EnlargeGapTo(inNumItems + kTextGapBufferBlockSize);
|
||||||
|
|
||||||
// Finally, read the data and put it into the buffer
|
// Finally, read the data and put it into the buffer
|
||||||
if (file->ReadAt(fileOffset, fBuffer + fGapIndex, inNumItems) > 0) {
|
if (file->ReadAt(fileOffset, fBuffer + fGapIndex, inNumItems) > 0) {
|
||||||
@@ -121,59 +121,13 @@ TextGapBuffer::RemoveRange(int32 start, int32 end)
|
|||||||
inAtIndex = (inAtIndex > fItemCount - 1) ? (fItemCount - 1) : inAtIndex;
|
inAtIndex = (inAtIndex > fItemCount - 1) ? (fItemCount - 1) : inAtIndex;
|
||||||
inAtIndex = (inAtIndex < 0) ? 0 : inAtIndex;
|
inAtIndex = (inAtIndex < 0) ? 0 : inAtIndex;
|
||||||
|
|
||||||
MoveGapTo(inAtIndex);
|
_MoveGapTo(inAtIndex);
|
||||||
|
|
||||||
fGapCount += inNumItems;
|
fGapCount += inNumItems;
|
||||||
fItemCount -= inNumItems;
|
fItemCount -= inNumItems;
|
||||||
|
|
||||||
if (fGapCount > kTextGapBufferBlockSize)
|
if (fGapCount > kTextGapBufferBlockSize)
|
||||||
SizeGapTo(kTextGapBufferBlockSize);
|
_ShrinkGapTo(kTextGapBufferBlockSize);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
TextGapBuffer::MoveGapTo(int32 toIndex)
|
|
||||||
{
|
|
||||||
if (toIndex == fGapIndex)
|
|
||||||
return;
|
|
||||||
if (toIndex > fItemCount) {
|
|
||||||
debugger("MoveGapTo: invalid toIndex supplied");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 srcIndex = 0;
|
|
||||||
int32 dstIndex = 0;
|
|
||||||
int32 count = 0;
|
|
||||||
if (toIndex > fGapIndex) {
|
|
||||||
srcIndex = fGapIndex + fGapCount;
|
|
||||||
dstIndex = fGapIndex;
|
|
||||||
count = toIndex - fGapIndex;
|
|
||||||
} else {
|
|
||||||
srcIndex = toIndex;
|
|
||||||
dstIndex = toIndex + fGapCount;
|
|
||||||
count = fGapIndex- toIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count > 0)
|
|
||||||
memmove(fBuffer + dstIndex, fBuffer + srcIndex, count);
|
|
||||||
|
|
||||||
fGapIndex = toIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
TextGapBuffer::SizeGapTo(long inCount)
|
|
||||||
{
|
|
||||||
if (inCount == fGapCount)
|
|
||||||
return;
|
|
||||||
|
|
||||||
fBuffer = (char*)realloc(fBuffer, fItemCount + inCount);
|
|
||||||
memmove(fBuffer + fGapIndex + inCount,
|
|
||||||
fBuffer + fGapIndex + fGapCount,
|
|
||||||
fBufferCount - (fGapIndex + fGapCount));
|
|
||||||
|
|
||||||
fGapCount = inCount;
|
|
||||||
fBufferCount = fItemCount + fGapCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -195,7 +149,6 @@ TextGapBuffer::GetString(int32 fromOffset, int32* _numBytes)
|
|||||||
result = fBuffer + fromOffset;
|
result = fBuffer + fromOffset;
|
||||||
if (!isStartBeforeGap)
|
if (!isStartBeforeGap)
|
||||||
result += fGapCount;
|
result += fGapCount;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (fScratchSize < numBytes) {
|
if (fScratchSize < numBytes) {
|
||||||
fScratchBuffer = (char*)realloc(fScratchBuffer, numBytes);
|
fScratchBuffer = (char*)realloc(fScratchBuffer, numBytes);
|
||||||
@@ -284,10 +237,10 @@ TextGapBuffer::Text()
|
|||||||
const char*
|
const char*
|
||||||
TextGapBuffer::RealText()
|
TextGapBuffer::RealText()
|
||||||
{
|
{
|
||||||
MoveGapTo(fItemCount);
|
_MoveGapTo(fItemCount);
|
||||||
|
|
||||||
if (fGapCount == 0)
|
if (fGapCount == 0)
|
||||||
SizeGapTo(kTextGapBufferBlockSize);
|
_EnlargeGapTo(kTextGapBufferBlockSize);
|
||||||
|
|
||||||
fBuffer[fItemCount] = '\0';
|
fBuffer[fItemCount] = '\0';
|
||||||
return fBuffer;
|
return fBuffer;
|
||||||
@@ -348,5 +301,65 @@ TextGapBuffer::SetPasswordMode(bool state)
|
|||||||
fPasswordMode = state;
|
fPasswordMode = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace BPrivate
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextGapBuffer::_MoveGapTo(int32 toIndex)
|
||||||
|
{
|
||||||
|
if (toIndex == fGapIndex)
|
||||||
|
return;
|
||||||
|
if (toIndex > fItemCount) {
|
||||||
|
debugger("MoveGapTo: invalid toIndex supplied");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 srcIndex = 0;
|
||||||
|
int32 dstIndex = 0;
|
||||||
|
int32 count = 0;
|
||||||
|
if (toIndex > fGapIndex) {
|
||||||
|
srcIndex = fGapIndex + fGapCount;
|
||||||
|
dstIndex = fGapIndex;
|
||||||
|
count = toIndex - fGapIndex;
|
||||||
|
} else {
|
||||||
|
srcIndex = toIndex;
|
||||||
|
dstIndex = toIndex + fGapCount;
|
||||||
|
count = fGapIndex- toIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0)
|
||||||
|
memmove(fBuffer + dstIndex, fBuffer + srcIndex, count);
|
||||||
|
|
||||||
|
fGapIndex = toIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextGapBuffer::_EnlargeGapTo(long inCount)
|
||||||
|
{
|
||||||
|
if (inCount == fGapCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fBuffer = (char*)realloc(fBuffer, fItemCount + inCount);
|
||||||
|
memmove(fBuffer + fGapIndex + inCount, fBuffer + fGapIndex + fGapCount,
|
||||||
|
fBufferCount - (fGapIndex + fGapCount));
|
||||||
|
|
||||||
|
fGapCount = inCount;
|
||||||
|
fBufferCount = fItemCount + fGapCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextGapBuffer::_ShrinkGapTo(long inCount)
|
||||||
|
{
|
||||||
|
if (inCount == fGapCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memmove(fBuffer + fGapIndex + inCount, fBuffer + fGapIndex + fGapCount,
|
||||||
|
fBufferCount - (fGapIndex + fGapCount));
|
||||||
|
fBuffer = (char*)realloc(fBuffer, fItemCount + inCount);
|
||||||
|
|
||||||
|
fGapCount = inCount;
|
||||||
|
fBufferCount = fItemCount + fGapCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|||||||
@@ -30,9 +30,6 @@ public:
|
|||||||
int32 amount, int32 atIndex);
|
int32 amount, int32 atIndex);
|
||||||
void RemoveRange(int32 start, int32 end);
|
void RemoveRange(int32 start, int32 end);
|
||||||
|
|
||||||
void MoveGapTo(int32 toIndex);
|
|
||||||
void SizeGapTo(int32 inCount);
|
|
||||||
|
|
||||||
bool FindChar(char inChar, int32 fromIndex,
|
bool FindChar(char inChar, int32 fromIndex,
|
||||||
int32* ioDelta);
|
int32* ioDelta);
|
||||||
|
|
||||||
@@ -49,7 +46,11 @@ public:
|
|||||||
bool PasswordMode() const;
|
bool PasswordMode() const;
|
||||||
void SetPasswordMode(bool);
|
void SetPasswordMode(bool);
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
|
void _MoveGapTo(int32 toIndex);
|
||||||
|
void _EnlargeGapTo(int32 inCount);
|
||||||
|
void _ShrinkGapTo(int32 inCount);
|
||||||
|
|
||||||
int32 fItemCount; // logical count
|
int32 fItemCount; // logical count
|
||||||
char* fBuffer; // allocated memory
|
char* fBuffer; // allocated memory
|
||||||
int32 fBufferCount; // physical count
|
int32 fBufferCount; // physical count
|
||||||
|
|||||||
Reference in New Issue
Block a user