-
Notifications
You must be signed in to change notification settings - Fork 396
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Sanitize text pasted into hex text boxes (squashed PR #3684)
* Sanitize text pasted into hex text boxes Trim `0x` and `$` prefixes and whitespace pasted into `HexTextBox` and `WatchValueBox`. Prevent pasting non-hex text. Add `ClipboardEventTextBox` control with `OnPaste` event * Fall back to trapping paste keyboard shortcuts on Linux * Adjust code style, seal `PasteEventArgs` * Use slightly more sophisticated shared method for sanitizing hex strings * Use moderately more sophisticated method for sanitizing hex strings * More `string.Empty` * Add some comments * Code style * Remove superfluous format check
- Loading branch information
Showing
5 changed files
with
168 additions
and
3 deletions.
There are no files selected for viewing
94 changes: 94 additions & 0 deletions
94
src/BizHawk.Client.EmuHawk/CustomControls/ClipboardEventTextBox.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
using System; | ||
using System.Windows.Forms; | ||
using BizHawk.Common; | ||
|
||
namespace BizHawk.Client.EmuHawk.CustomControls | ||
{ | ||
public class ClipboardEventTextBox : TextBox | ||
{ | ||
protected override void WndProc(ref Message m) | ||
{ | ||
// WM_PASTE is also sent when pasting through the OS context menu, but doesn't work on Mono | ||
const int WM_PASTE = 0x302; | ||
|
||
if (m.Msg is WM_PASTE && !OSTailoredCode.IsUnixHost) | ||
{ | ||
if (OnPasteInternal()) | ||
{ | ||
return; | ||
} | ||
} | ||
|
||
base.WndProc(ref m); | ||
} | ||
|
||
protected override bool ProcessCmdKey(ref Message m, Keys keyData) | ||
{ | ||
if (!ReadOnly && OSTailoredCode.IsUnixHost && keyData is (Keys.Control | Keys.V) or (Keys.Shift | Keys.Insert)) | ||
{ | ||
return OnPasteInternal(); | ||
} | ||
|
||
return base.ProcessCmdKey(ref m, keyData); | ||
} | ||
|
||
/// <returns><see langword="true"/> if regular paste handling should be prevented.</returns> | ||
private bool OnPasteInternal() | ||
{ | ||
bool containsText; | ||
string text; | ||
|
||
try | ||
{ | ||
containsText = Clipboard.ContainsText(); | ||
text = containsText ? Clipboard.GetText() : string.Empty; | ||
} | ||
catch (Exception) | ||
{ | ||
// Clipboard is busy? No idea if this ever happens in practice | ||
return true; | ||
} | ||
|
||
var args = new PasteEventArgs(containsText, text); | ||
OnPaste(args); | ||
return args.Handled; | ||
} | ||
|
||
protected virtual void OnPaste(PasteEventArgs e) | ||
{ } | ||
|
||
/// <summary> | ||
/// Paste <paramref name="text"/> at selected position without exceeding the <see cref="TextBoxBase.MaxLength"/> limit. | ||
/// The pasted string will be truncated if necessary. | ||
/// </summary> | ||
/// <remarks> | ||
/// Does not raise <see cref="OnPaste"/>. | ||
/// </remarks> | ||
public void PasteWithMaxLength(string text) | ||
{ | ||
if (MaxLength > 0) | ||
{ | ||
var availableLength = MaxLength - TextLength + SelectionLength; | ||
if (text.Length > availableLength) | ||
{ | ||
text = text.Substring(startIndex: 0, length: availableLength); | ||
} | ||
} | ||
Paste(text); | ||
} | ||
|
||
protected sealed class PasteEventArgs : EventArgs | ||
{ | ||
public bool ContainsText { get; } | ||
public string Text { get; } | ||
/// <summary>Prevents regular paste handling if set to <see langword="true"/>.</summary> | ||
public bool Handled { get; set; } | ||
|
||
public PasteEventArgs(bool containsText, string text) | ||
{ | ||
ContainsText = containsText; | ||
Text = text; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
src/BizHawk.Tests/Common/StringExtensions/NumericStringExtensionTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
using BizHawk.Common.StringExtensions; | ||
|
||
namespace BizHawk.Tests.Common.StringExtensions | ||
{ | ||
[TestClass] | ||
public class NumericStringExtensionTests | ||
{ | ||
[TestMethod] | ||
public void TesCleanHex() | ||
{ | ||
Assert.AreEqual("0123456789ABCDEFABCDEF", "0123456789ABCDEFabcdef".CleanHex()); | ||
Assert.AreEqual("ABCDEF", "0xABCDEF".CleanHex()); | ||
Assert.AreEqual("ABCDEF", "$ABCDEF".CleanHex()); | ||
Assert.AreEqual("ABCDEF", " AB CD\nEF ".CleanHex()); | ||
Assert.AreEqual("ABCDEF", " 0xABCDEF ".CleanHex()); | ||
|
||
Assert.AreEqual(string.Empty, (null as string).CleanHex()); | ||
Assert.AreEqual(string.Empty, string.Empty.CleanHex()); | ||
Assert.AreEqual(string.Empty, "0x$ABCDEF".CleanHex()); | ||
Assert.AreEqual(string.Empty, "$0xABCDEF".CleanHex()); | ||
Assert.AreEqual(string.Empty, "$$ABCDEF".CleanHex()); | ||
Assert.AreEqual(string.Empty, "ABCDEF$".CleanHex()); | ||
Assert.AreEqual(string.Empty, "A!B.C(DE)F".CleanHex()); | ||
} | ||
} | ||
} |