mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-11-04 12:51:48 +00:00
Validate input of edit fields for type char
This commit is contained in:
@@ -1,4 +1,11 @@
|
|||||||
using System;
|
using GlitchyEngine.Core;
|
||||||
|
using GlitchyEngine.Extensions;
|
||||||
|
using GlitchyEngine.Graphics;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
using GlitchyEngine.Math.Attributes;
|
||||||
|
using ImGuiNET;
|
||||||
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
@@ -10,12 +17,7 @@ using System.Reflection;
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using GlitchyEngine.Core;
|
using System.Text.Unicode;
|
||||||
using GlitchyEngine.Extensions;
|
|
||||||
using GlitchyEngine.Graphics;
|
|
||||||
using GlitchyEngine.Math;
|
|
||||||
using GlitchyEngine.Math.Attributes;
|
|
||||||
using ImGuiNET;
|
|
||||||
using Component = GlitchyEngine.Core.Component;
|
using Component = GlitchyEngine.Core.Component;
|
||||||
|
|
||||||
namespace GlitchyEngine.Editor;
|
namespace GlitchyEngine.Editor;
|
||||||
@@ -327,9 +329,6 @@ internal class EntityEditor
|
|||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
// TODO: Allow escaped unicode chars \u XXXX
|
|
||||||
// TODO: Add text input validation, so that it isn't possible to type invalid chars
|
|
||||||
|
|
||||||
char* value = stackalloc char[4];
|
char* value = stackalloc char[4];
|
||||||
switch((char)reference!)
|
switch((char)reference!)
|
||||||
{
|
{
|
||||||
@@ -374,20 +373,143 @@ internal class EntityEditor
|
|||||||
// Place string delimiter after encoded UTF8 sequence.
|
// Place string delimiter after encoded UTF8 sequence.
|
||||||
buffer[encodedBytes] = (byte)'\0';
|
buffer[encodedBytes] = (byte)'\0';
|
||||||
|
|
||||||
if (ImGui.InputText(fieldId, (IntPtr)buffer, 8))
|
// Makes sure the data of a char text field is always valid or can be extended to be a valid char.
|
||||||
|
int CharTextFieldFilter(ImGuiInputTextCallbackData* data)
|
||||||
{
|
{
|
||||||
if (buffer[0] == '\\' && buffer[1] != '\0')
|
try
|
||||||
{
|
{
|
||||||
newValue = (char)buffer[1] switch
|
Span<byte> span = new Span<byte>(data->Buf, data->BufTextLen);
|
||||||
|
|
||||||
|
if (span.IsEmpty)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (span[0] == '\\')
|
||||||
{
|
{
|
||||||
'a' => newValue = '\a',
|
// It's just the backslash, so we don't need to do anything yet.
|
||||||
'b' => newValue = '\b',
|
if (span.Length == 1)
|
||||||
'f' => newValue = '\f',
|
return 0;
|
||||||
'n' => newValue = '\n',
|
|
||||||
'r' => newValue = '\r',
|
if (span[1] == 'a' || span[1] == 'b' || span[1] == 'f' || span[1] == 'n' ||
|
||||||
't' => newValue = '\t',
|
span[1] == 'r' || span[1] == 't' || span[1] == 'v' || span[1] == '\0')
|
||||||
'v' => newValue = '\v',
|
{
|
||||||
_ => newValue = '\\'
|
if (span.Length == 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Handle simply ascii escape sequence
|
||||||
|
if (span[2] != '\0')
|
||||||
|
{
|
||||||
|
span[2] = 0;
|
||||||
|
data->BufTextLen = 2;
|
||||||
|
data->BufDirty = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (span[1] == 'u')
|
||||||
|
{
|
||||||
|
// Handle unicode escape sequence \uXXXX
|
||||||
|
// Check if the next four characters are valid hex digits
|
||||||
|
for (int i = 2; i < span.Length; i++)
|
||||||
|
{
|
||||||
|
char c = (char)span[i];
|
||||||
|
|
||||||
|
if (c == '\0')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Uri.IsHexDigit(c))
|
||||||
|
{
|
||||||
|
span[i] = 0;
|
||||||
|
data->BufTextLen = i;
|
||||||
|
data->BufDirty = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (span.Length > 6)
|
||||||
|
{
|
||||||
|
span[6] = 0;
|
||||||
|
data->BufTextLen = 6;
|
||||||
|
data->BufDirty = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (span[1] != '\0')
|
||||||
|
{
|
||||||
|
span[1] = 0;
|
||||||
|
data->BufTextLen = 1;
|
||||||
|
data->BufDirty = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var status = Rune.DecodeFromUtf8(span, out Rune rune, out int bytesConsumed);
|
||||||
|
|
||||||
|
// invalid UTF-8 oder Unicode-symbol needs two UTF-16 chars.
|
||||||
|
if (status != OperationStatus.Done || !rune.IsBmp)
|
||||||
|
{
|
||||||
|
span[0] = 0;
|
||||||
|
data->BufTextLen = 0;
|
||||||
|
data->BufDirty = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: if we want to support Rune as a type, we "just" need to disable this if-check
|
||||||
|
// Cut off everything after the first C# char (which is the first UTF-16 char of the Rune)
|
||||||
|
if (bytesConsumed < span.Length)
|
||||||
|
{
|
||||||
|
span[bytesConsumed] = 0;
|
||||||
|
data->BufTextLen = bytesConsumed;
|
||||||
|
data->BufDirty = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error($"Failed to process char field {fieldName}: {e.Message}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make space for the hex code of the char after the textbox
|
||||||
|
ImGui.SetNextItemWidth(ImGui.CalcItemWidth() / 2);
|
||||||
|
|
||||||
|
if (ImGui.InputText(fieldId, (IntPtr)buffer, 8, ImGuiInputTextFlags.CallbackEdit, CharTextFieldFilter))
|
||||||
|
{
|
||||||
|
var dataSpan = new ReadOnlySpan<byte>(buffer, 8);
|
||||||
|
|
||||||
|
if (dataSpan[0] == '\\' && dataSpan[1] == 'u')
|
||||||
|
{
|
||||||
|
// Decode unicode escape sequence \uXXXX
|
||||||
|
string hex = Encoding.UTF8.GetString(dataSpan[2..]);
|
||||||
|
if (int.TryParse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int codePoint))
|
||||||
|
{
|
||||||
|
newValue = (char)codePoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (dataSpan[0] == '\\' && dataSpan[1] != '\0')
|
||||||
|
{
|
||||||
|
newValue = (char)dataSpan[1] switch
|
||||||
|
{
|
||||||
|
'a' => '\a',
|
||||||
|
'b' => '\b',
|
||||||
|
'f' => '\f',
|
||||||
|
'n' => '\n',
|
||||||
|
'r' => '\r',
|
||||||
|
't' => '\t',
|
||||||
|
'v' => '\v',
|
||||||
|
_ => '\\'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -397,7 +519,11 @@ internal class EntityEditor
|
|||||||
|
|
||||||
newValue = value[0];
|
newValue = value[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show the char as hex code
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.TextUnformatted($"(U+{(ushort)(char)reference:X4})");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (fieldType == typeof(byte))
|
else if (fieldType == typeof(byte))
|
||||||
|
|||||||
Reference in New Issue
Block a user