fix infinite loop

This commit is contained in:
UnknownShadow200 2018-07-24 19:13:01 +10:00
parent 22cd5dc64a
commit 695cd9ab52
3 changed files with 120 additions and 20 deletions

View File

@ -244,18 +244,18 @@ namespace ClassicalSharp.Gui.Widgets {
for (; i < total; i++) {
if (!(chars[i] == 'h' || chars[i] == '&')) continue;
int left = total - i;
if (left < prefixLen) return -1;
if (left < prefixLen) return total;
// colour codes at start of URL
int start = i;
while (left >= 2 && chars[i] == '&') { left -= 2; i += 2; }
if (left < prefixLen) continue;
// Starts with "http" ?
// Starts with "http"
if (chars[i] != 'h' || chars[i + 1] != 't' || chars[i + 2] != 't' || chars[i + 3] != 'p') continue;
left -= 4; i += 4;
// And then with "s://" or "://" ?
// And then with "s://" or "://"
if (chars[i] == 's') { left--; i++; }
if (left >= 3 && chars[i] == ':' && chars[i + 1] == '/' && chars[i + 2] == '/') return start;
}
@ -265,7 +265,7 @@ namespace ClassicalSharp.Gui.Widgets {
unsafe int UrlEnd(char* chars, int total, int* begs, int i) {
int start = i;
for (; i < total && chars[i] != ' '; i++) {
// Is this character the start of a line?
// Is this character the start of a line
bool isBeg = false;
for (int j = 0; j < lines.Length; i++) {
if (j == begs[j]) { isBeg = true; break; }
@ -275,7 +275,7 @@ namespace ClassicalSharp.Gui.Widgets {
if (!isBeg || i == start) continue;
if (chars[i] != '>') break;
// Does this line start with "> ", making it a multiline ?
// Does this line start with "> ", making it a multiline
int next = i + 1, left = total - next;
while (left >= 2 && chars[next] == '&') { left -= 2; next += 2; }
if (left == 0 || chars[next] != ' ') break;
@ -324,22 +324,21 @@ namespace ClassicalSharp.Gui.Widgets {
total += line.Length; ends[i] = total;
}
int urlEnd = 0;
int end = 0; Portion bit = default(Portion);
for (;;) {
int nextUrlStart = NextUrl(chars, urlEnd, total);
int nextStart = NextUrl(chars, end, total);
// add normal portion between urls
Portion bit = default(Portion); bit.Beg = urlEnd;
bit.Len = nextUrlStart - urlEnd;
bit.Beg = end;
bit.Len = nextStart - end;
Output(bit, begs[target], ends[target], ref portions);
if (nextUrlStart == total) break;
urlEnd = UrlEnd(chars, total, begs, nextUrlStart);
if (nextStart == total) break;
end = UrlEnd(chars, total, begs, nextStart);
// add this url portion
bit = default(Portion);
bit.Beg = nextUrlStart;
bit.Len = (urlEnd - nextUrlStart) | 0x8000;
bit.Beg = nextStart;
bit.Len = (end - nextStart) | 0x8000;
Output(bit, begs[target], ends[target], ref portions);
}
return (int)(portions - start);

View File

@ -1008,12 +1008,8 @@ static bool ChatScreen_HandlesMouseDown(struct GuiElem* elem, Int32 x, Int32 y,
TextGroupWidget_GetSelected(&screen->Chat, &text, x, y);
if (text.length == 0) return false;
UChar urlBuffer[String_BufferSize(TEXTGROUPWIDGET_LEN)];
String url = String_InitAndClearArray(urlBuffer);
String_AppendColorless(&url, &text);
if (Utils_IsUrlPrefix(&url, 0)) {
struct Screen* overlay = UrlWarningOverlay_MakeInstance(&url);
if (Utils_IsUrlPrefix(&text, 0)) {
struct Screen* overlay = UrlWarningOverlay_MakeInstance(&text);
Gui_ShowOverlay(overlay, false);
} else if (Game_ClickableChat) {
InputWidget_AppendString(&screen->Input.Base, &text);

View File

@ -2315,6 +2315,111 @@ static void TextGroupWidget_UpdateDimensions(struct TextGroupWidget* widget) {
Widget_Reposition(widget);
}
Int32 TextGroupWidget_NextUrl(UChar* chars, Int32 i, Int32 total) {
for (; i < total; i++) {
if (!(chars[i] == 'h' || chars[i] == '&')) continue;
Int32 left = total - i;
if (left < prefixLen) return total;
/* colour codes at start of URL */
Int32 start = i;
while (left >= 2 && chars[i] == '&') { left -= 2; i += 2; }
if (left < prefixLen) continue;
/* Starts with "http" */
if (chars[i] != 'h' || chars[i + 1] != 't' || chars[i + 2] != 't' || chars[i + 3] != 'p') continue;
left -= 4; i += 4;
/* And then with "s://" or "://" */
if (chars[i] == 's') { left--; i++; }
if (left >= 3 && chars[i] == ':' && chars[i + 1] == '/' && chars[i + 2] == '/') return start;
}
return total;
}
Int32 TextGroupWidget_UrlEnd(UChar* chars, Int32 total, Int32* begs, Int32 i) {
Int32 start = i, j;
for (; i < total && chars[i] != ' '; i++) {
/* Is this character the start of a line */
bool isBeg = false;
for (j = 0; j < lines.Length; i++) {
if (j == begs[j]) { isBeg = true; break; }
}
/* Definitely not a multilined URL */
if (!isBeg || i == start) continue;
if (chars[i] != '>') break;
/* Does this line start with "> ", making it a multiline */
Int32 next = i + 1, left = total - next;
while (left >= 2 && chars[next] == '&') { left -= 2; next += 2; }
if (left == 0 || chars[next] != ' ') break;
i = next;
}
return i;
}
void TextGroupWidget_Output(struct Portion bit, Int32 lineBeg, Int32 lineEnd, struct Portion** portions) {
if (bit.Beg >= lineEnd || bit.Len == 0) return;
bit.LineBeg = bit.Beg;
bit.LineLen = bit.Len & 0x7FFF;
/* Adjust this portion to be within this line */
if (bit.Beg >= lineBeg) {
} else if (bit.Beg + bit.LineLen > lineBeg) {
/* Adjust start of portion to be within this line */
Int32 underBy = lineBeg - bit.Beg;
bit.LineBeg += underBy; bit.LineLen -= underBy;
} else { return; }
/* Limit length of portion to be within this line */
Int32 overBy = (bit.LineBeg + bit.LineLen) - lineEnd;
if (overBy > 0) bit.LineLen -= overBy;
bit.LineBeg -= lineBeg;
if (bit.LineLen == 0) return;
struct Portion* cur = *portions; *cur++ = bit; *portions = cur;
}
struct Portion { Int16 Beg, Len, LineBeg, LineLen; };
Int32 TextGroupWidget_Reduce(UChar* chars, Int32 target, struct Portion* portions) {
struct Portion* start = portions;
Int32 total = 0, i, j;
Int32 begs[TEXTGROUPWIDGET_MAX_LINES];
Int32 ends[TEXTGROUPWIDGET_MAX_LINES];
for (i = 0; i < lines.Length; i++) {
string line = lines[i];
begs[i] = -1; ends[i] = -1;
if (line == null) continue;
begs[i] = total;
for (j = 0; j < line.Length; j++) { chars[total + j] = line[j]; }
total += line.Length; ends[i] = total;
}
Int32 end = 0; struct Portion bit;
for (;;) {
Int32 nextStart = NextUrl(chars, end, total);
/* add normal portion between urls */
bit.Beg = end;
bit.Len = nextStart - end;
Output(bit, begs[target], ends[target], &portions);
if (nextStart == total) break;
end = UrlEnd(chars, total, begs, nextStart);
/* add this url portion */
bit.Beg = nextStart;
bit.Len = (end - nextStart) | 0x8000;
Output(bit, begs[target], ends[target], &portions);
}
return (Int32)(portions - start);
}
String TextGroupWidget_UNSAFE_Get(struct TextGroupWidget* widget, Int32 i) {
UChar* buffer = widget->Buffer + i * TEXTGROUPWIDGET_LEN;
UInt16 length = widget->LineLengths[i];