Fix #9217 - BTextView should clamp given offsets to avoid crashes
* applied patch provided with ticket, thanks! * extended patch to implement offset clamping for all public methods of BTextView and remove some checks from private methods to define a clear baseline for sanity of offsets used in the code
This commit is contained in:
+115
-42
@@ -1258,6 +1258,11 @@ void
|
|||||||
BTextView::Insert(int32 startOffset, const char *inText, int32 inLength,
|
BTextView::Insert(int32 startOffset, const char *inText, int32 inLength,
|
||||||
const text_run_array *inRuns)
|
const text_run_array *inRuns)
|
||||||
{
|
{
|
||||||
|
// pin offset at reasonable values
|
||||||
|
if (startOffset < 0)
|
||||||
|
startOffset = 0;
|
||||||
|
else if (startOffset > fText->Length())
|
||||||
|
startOffset = fText->Length();
|
||||||
if (inText != NULL && inLength > 0)
|
if (inText != NULL && inLength > 0)
|
||||||
_DoInsertText(inText, strnlen(inText, inLength), startOffset, inRuns);
|
_DoInsertText(inText, strnlen(inText, inLength), startOffset, inRuns);
|
||||||
}
|
}
|
||||||
@@ -1280,6 +1285,17 @@ void
|
|||||||
BTextView::Delete(int32 startOffset, int32 endOffset)
|
BTextView::Delete(int32 startOffset, int32 endOffset)
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
|
||||||
|
// pin offsets at reasonable values
|
||||||
|
if (startOffset < 0)
|
||||||
|
startOffset = 0;
|
||||||
|
else if (startOffset > fText->Length())
|
||||||
|
startOffset = fText->Length();
|
||||||
|
if (endOffset < 0)
|
||||||
|
endOffset = 0;
|
||||||
|
else if (endOffset > fText->Length())
|
||||||
|
endOffset = fText->Length();
|
||||||
|
|
||||||
// anything to delete?
|
// anything to delete?
|
||||||
if (startOffset == endOffset)
|
if (startOffset == endOffset)
|
||||||
return;
|
return;
|
||||||
@@ -1544,18 +1560,20 @@ BTextView::Select(int32 startOffset, int32 endOffset)
|
|||||||
|
|
||||||
_CancelInputMethod();
|
_CancelInputMethod();
|
||||||
|
|
||||||
// a negative selection?
|
|
||||||
if (startOffset > endOffset)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// pin offsets at reasonable values
|
// pin offsets at reasonable values
|
||||||
if (startOffset < 0)
|
if (startOffset < 0)
|
||||||
startOffset = 0;
|
startOffset = 0;
|
||||||
|
else if (startOffset > fText->Length())
|
||||||
|
startOffset = fText->Length();
|
||||||
if (endOffset < 0)
|
if (endOffset < 0)
|
||||||
endOffset = 0;
|
endOffset = 0;
|
||||||
else if (endOffset > fText->Length())
|
else if (endOffset > fText->Length())
|
||||||
endOffset = fText->Length();
|
endOffset = fText->Length();
|
||||||
|
|
||||||
|
// a negative selection?
|
||||||
|
if (startOffset > endOffset)
|
||||||
|
return;
|
||||||
|
|
||||||
// is the new selection any different from the current selection?
|
// is the new selection any different from the current selection?
|
||||||
if (startOffset == fSelStart && endOffset == fSelEnd)
|
if (startOffset == fSelStart && endOffset == fSelEnd)
|
||||||
return;
|
return;
|
||||||
@@ -1733,6 +1751,16 @@ BTextView::SetRunArray(int32 startOffset, int32 endOffset,
|
|||||||
oneRun.runs[0] = inRuns->runs[0];
|
oneRun.runs[0] = inRuns->runs[0];
|
||||||
oneRun.runs[0].offset = 0;
|
oneRun.runs[0].offset = 0;
|
||||||
runs = &oneRun;
|
runs = &oneRun;
|
||||||
|
} else {
|
||||||
|
// pin offsets at reasonable values
|
||||||
|
if (startOffset < 0)
|
||||||
|
startOffset = 0;
|
||||||
|
else if (startOffset > fText->Length())
|
||||||
|
startOffset = fText->Length();
|
||||||
|
if (endOffset < 0)
|
||||||
|
endOffset = 0;
|
||||||
|
else if (endOffset > fText->Length())
|
||||||
|
endOffset = fText->Length();
|
||||||
}
|
}
|
||||||
|
|
||||||
_SetRunArray(startOffset, endOffset, runs);
|
_SetRunArray(startOffset, endOffset, runs);
|
||||||
@@ -1754,6 +1782,16 @@ BTextView::SetRunArray(int32 startOffset, int32 endOffset,
|
|||||||
text_run_array *
|
text_run_array *
|
||||||
BTextView::RunArray(int32 startOffset, int32 endOffset, int32 *outSize) const
|
BTextView::RunArray(int32 startOffset, int32 endOffset, int32 *outSize) const
|
||||||
{
|
{
|
||||||
|
// pin offsets at reasonable values
|
||||||
|
if (startOffset < 0)
|
||||||
|
startOffset = 0;
|
||||||
|
else if (startOffset > fText->Length())
|
||||||
|
startOffset = fText->Length();
|
||||||
|
if (endOffset < 0)
|
||||||
|
endOffset = 0;
|
||||||
|
else if (endOffset > fText->Length())
|
||||||
|
endOffset = fText->Length();
|
||||||
|
|
||||||
STEStyleRange* styleRange = fStyles->GetStyleRange(startOffset,
|
STEStyleRange* styleRange = fStyles->GetStyleRange(startOffset,
|
||||||
endOffset - 1);
|
endOffset - 1);
|
||||||
if (styleRange == NULL)
|
if (styleRange == NULL)
|
||||||
@@ -1781,6 +1819,12 @@ BTextView::RunArray(int32 startOffset, int32 endOffset, int32 *outSize) const
|
|||||||
int32
|
int32
|
||||||
BTextView::LineAt(int32 offset) const
|
BTextView::LineAt(int32 offset) const
|
||||||
{
|
{
|
||||||
|
// pin offset at reasonable values
|
||||||
|
if (offset < 0)
|
||||||
|
offset = 0;
|
||||||
|
else if (offset > fText->Length())
|
||||||
|
offset = fText->Length();
|
||||||
|
|
||||||
int32 lineNum = _LineAt(offset);
|
int32 lineNum = _LineAt(offset);
|
||||||
if (_IsOnEmptyLastLine(offset))
|
if (_IsOnEmptyLastLine(offset))
|
||||||
lineNum++;
|
lineNum++;
|
||||||
@@ -1811,6 +1855,12 @@ BTextView::LineAt(BPoint point) const
|
|||||||
BPoint
|
BPoint
|
||||||
BTextView::PointAt(int32 inOffset, float *outHeight) const
|
BTextView::PointAt(int32 inOffset, float *outHeight) const
|
||||||
{
|
{
|
||||||
|
// pin offset at reasonable values
|
||||||
|
if (inOffset < 0)
|
||||||
|
inOffset = 0;
|
||||||
|
else if (inOffset > fText->Length())
|
||||||
|
inOffset = fText->Length();
|
||||||
|
|
||||||
// TODO: Cleanup.
|
// TODO: Cleanup.
|
||||||
int32 lineNum = _LineAt(inOffset);
|
int32 lineNum = _LineAt(inOffset);
|
||||||
STELine* line = (*fLines)[lineNum];
|
STELine* line = (*fLines)[lineNum];
|
||||||
@@ -1971,6 +2021,21 @@ BTextView::OffsetAt(int32 line) const
|
|||||||
void
|
void
|
||||||
BTextView::FindWord(int32 inOffset, int32 *outFromOffset, int32 *outToOffset)
|
BTextView::FindWord(int32 inOffset, int32 *outFromOffset, int32 *outToOffset)
|
||||||
{
|
{
|
||||||
|
if (inOffset < 0) {
|
||||||
|
if (outFromOffset)
|
||||||
|
*outFromOffset = 0;
|
||||||
|
if (outToOffset)
|
||||||
|
*outToOffset = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (inOffset > fText->Length()) {
|
||||||
|
if (outFromOffset)
|
||||||
|
*outFromOffset = fText->Length();
|
||||||
|
if (outToOffset)
|
||||||
|
*outToOffset = fText->Length();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (outFromOffset)
|
if (outFromOffset)
|
||||||
*outFromOffset = _PreviousWordBoundary(inOffset);
|
*outFromOffset = _PreviousWordBoundary(inOffset);
|
||||||
|
|
||||||
@@ -2100,7 +2165,11 @@ BTextView::TextHeight(int32 startLine, int32 endLine) const
|
|||||||
const int32 numLines = fLines->NumLines();
|
const int32 numLines = fLines->NumLines();
|
||||||
if (startLine < 0)
|
if (startLine < 0)
|
||||||
startLine = 0;
|
startLine = 0;
|
||||||
if (endLine > numLines - 1)
|
else if (startLine > numLines - 1)
|
||||||
|
startLine = numLines - 1;
|
||||||
|
if (endLine < 0)
|
||||||
|
endLine = 0;
|
||||||
|
else if (endLine > numLines - 1)
|
||||||
endLine = numLines - 1;
|
endLine = numLines - 1;
|
||||||
|
|
||||||
float height = (*fLines)[endLine + 1]->origin
|
float height = (*fLines)[endLine + 1]->origin
|
||||||
@@ -2123,6 +2192,16 @@ BTextView::GetTextRegion(int32 startOffset, int32 endOffset,
|
|||||||
|
|
||||||
outRegion->MakeEmpty();
|
outRegion->MakeEmpty();
|
||||||
|
|
||||||
|
// pin offsets at reasonable values
|
||||||
|
if (startOffset < 0)
|
||||||
|
startOffset = 0;
|
||||||
|
else if (startOffset > fText->Length())
|
||||||
|
startOffset = fText->Length();
|
||||||
|
if (endOffset < 0)
|
||||||
|
endOffset = 0;
|
||||||
|
else if (endOffset > fText->Length())
|
||||||
|
endOffset = fText->Length();
|
||||||
|
|
||||||
// return an empty region if the range is invalid
|
// return an empty region if the range is invalid
|
||||||
if (startOffset >= endOffset)
|
if (startOffset >= endOffset)
|
||||||
return;
|
return;
|
||||||
@@ -2177,6 +2256,12 @@ BTextView::GetTextRegion(int32 startOffset, int32 endOffset,
|
|||||||
void
|
void
|
||||||
BTextView::ScrollToOffset(int32 inOffset)
|
BTextView::ScrollToOffset(int32 inOffset)
|
||||||
{
|
{
|
||||||
|
// pin offset at reasonable values
|
||||||
|
if (inOffset < 0)
|
||||||
|
inOffset = 0;
|
||||||
|
else if (inOffset > fText->Length())
|
||||||
|
inOffset = fText->Length();
|
||||||
|
|
||||||
BRect bounds = Bounds();
|
BRect bounds = Bounds();
|
||||||
float lineHeight = 0.0;
|
float lineHeight = 0.0;
|
||||||
float xDiff = 0.0;
|
float xDiff = 0.0;
|
||||||
@@ -2228,7 +2313,16 @@ BTextView::ScrollToSelection()
|
|||||||
void
|
void
|
||||||
BTextView::Highlight(int32 startOffset, int32 endOffset)
|
BTextView::Highlight(int32 startOffset, int32 endOffset)
|
||||||
{
|
{
|
||||||
// get real
|
// pin offsets at reasonable values
|
||||||
|
if (startOffset < 0)
|
||||||
|
startOffset = 0;
|
||||||
|
else if (startOffset > fText->Length())
|
||||||
|
startOffset = fText->Length();
|
||||||
|
if (endOffset < 0)
|
||||||
|
endOffset = 0;
|
||||||
|
else if (endOffset > fText->Length())
|
||||||
|
endOffset = fText->Length();
|
||||||
|
|
||||||
if (startOffset >= endOffset)
|
if (startOffset >= endOffset)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -3105,8 +3199,17 @@ void
|
|||||||
BTextView::DeleteText(int32 fromOffset, int32 toOffset)
|
BTextView::DeleteText(int32 fromOffset, int32 toOffset)
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
// sanity checking
|
|
||||||
if (fromOffset >= toOffset || fromOffset < 0 || toOffset > fText->Length())
|
if (fromOffset < 0)
|
||||||
|
fromOffset = 0;
|
||||||
|
else if (fromOffset > fText->Length())
|
||||||
|
fromOffset = fText->Length();
|
||||||
|
if (toOffset < 0)
|
||||||
|
toOffset = 0;
|
||||||
|
else if (toOffset > fText->Length())
|
||||||
|
toOffset = fText->Length();
|
||||||
|
|
||||||
|
if (fromOffset >= toOffset)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// set nullStyle to style at beginning of range
|
// set nullStyle to style at beginning of range
|
||||||
@@ -4023,9 +4126,6 @@ BTextView::_FindLineBreak(int32 fromOffset, float *outAscent, float *outDescent,
|
|||||||
int32
|
int32
|
||||||
BTextView::_PreviousWordBoundary(int32 offset)
|
BTextView::_PreviousWordBoundary(int32 offset)
|
||||||
{
|
{
|
||||||
if (offset <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
uint32 charType = _CharClassification(offset);
|
uint32 charType = _CharClassification(offset);
|
||||||
int32 previous;
|
int32 previous;
|
||||||
while (offset > 0) {
|
while (offset > 0) {
|
||||||
@@ -4042,10 +4142,7 @@ BTextView::_PreviousWordBoundary(int32 offset)
|
|||||||
int32
|
int32
|
||||||
BTextView::_NextWordBoundary(int32 offset)
|
BTextView::_NextWordBoundary(int32 offset)
|
||||||
{
|
{
|
||||||
int32 textLen = TextLength();
|
int32 textLen = fText->Length();
|
||||||
if (offset >= textLen)
|
|
||||||
return textLen;
|
|
||||||
|
|
||||||
uint32 charType = _CharClassification(offset);
|
uint32 charType = _CharClassification(offset);
|
||||||
while (offset < textLen) {
|
while (offset < textLen) {
|
||||||
offset = _NextInitialByte(offset);
|
offset = _NextInitialByte(offset);
|
||||||
@@ -4087,10 +4184,7 @@ BTextView::_PreviousWordStart(int32 offset)
|
|||||||
int32
|
int32
|
||||||
BTextView::_NextWordEnd(int32 offset)
|
BTextView::_NextWordEnd(int32 offset)
|
||||||
{
|
{
|
||||||
int32 textLen = TextLength();
|
int32 textLen = fText->Length();
|
||||||
if (offset >= textLen)
|
|
||||||
return textLen;
|
|
||||||
|
|
||||||
if (_CharClassification(offset) != CHAR_CLASS_DEFAULT) {
|
if (_CharClassification(offset) != CHAR_CLASS_DEFAULT) {
|
||||||
// skip non-word characters
|
// skip non-word characters
|
||||||
while (offset < textLen) {
|
while (offset < textLen) {
|
||||||
@@ -4497,10 +4591,6 @@ BTextView::_RequestDrawLines(int32 startLine, int32 endLine)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
long maxLine = fLines->NumLines() - 1;
|
long maxLine = fLines->NumLines() - 1;
|
||||||
if (startLine < 0)
|
|
||||||
startLine = 0;
|
|
||||||
if (endLine > maxLine)
|
|
||||||
endLine = maxLine;
|
|
||||||
|
|
||||||
STELine *from = (*fLines)[startLine];
|
STELine *from = (*fLines)[startLine];
|
||||||
STELine *to = endLine == maxLine ? NULL : (*fLines)[endLine + 1];
|
STELine *to = endLine == maxLine ? NULL : (*fLines)[endLine + 1];
|
||||||
@@ -5142,22 +5232,6 @@ void
|
|||||||
BTextView::_SetRunArray(int32 startOffset, int32 endOffset,
|
BTextView::_SetRunArray(int32 startOffset, int32 endOffset,
|
||||||
const text_run_array *inRuns)
|
const text_run_array *inRuns)
|
||||||
{
|
{
|
||||||
if (startOffset > endOffset)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const int32 textLength = fText->Length();
|
|
||||||
|
|
||||||
// pin offsets at reasonable values
|
|
||||||
if (startOffset < 0)
|
|
||||||
startOffset = 0;
|
|
||||||
else if (startOffset > textLength)
|
|
||||||
startOffset = textLength;
|
|
||||||
|
|
||||||
if (endOffset < 0)
|
|
||||||
endOffset = 0;
|
|
||||||
else if (endOffset > textLength)
|
|
||||||
endOffset = textLength;
|
|
||||||
|
|
||||||
const int32 numStyles = inRuns->count;
|
const int32 numStyles = inRuns->count;
|
||||||
if (numStyles > 0) {
|
if (numStyles > 0) {
|
||||||
const text_run *theRun = &inRuns->runs[0];
|
const text_run *theRun = &inRuns->runs[0];
|
||||||
@@ -5255,9 +5329,8 @@ BTextView::_CharClassification(int32 offset) const
|
|||||||
int32
|
int32
|
||||||
BTextView::_NextInitialByte(int32 offset) const
|
BTextView::_NextInitialByte(int32 offset) const
|
||||||
{
|
{
|
||||||
int32 textLength = TextLength();
|
if (offset >= fText->Length())
|
||||||
if (offset >= textLength)
|
return offset;
|
||||||
return textLength;
|
|
||||||
|
|
||||||
for (++offset; (ByteAt(offset) & 0xC0) == 0x80; ++offset)
|
for (++offset; (ByteAt(offset) & 0xC0) == 0x80; ++offset)
|
||||||
;
|
;
|
||||||
|
|||||||
Reference in New Issue
Block a user