From 94dcf781daa3aa7d0ff8c726619db6a14173ad95 Mon Sep 17 00:00:00 2001 From: fangrong Date: Fri, 2 Aug 2024 18:30:11 +0800 Subject: [PATCH] HexBox now support multi encoding --- Be.Windows.Forms.HexBox/ByteCharConverters.cs | 24 ++- Be.Windows.Forms.HexBox/HexBox.cs | 77 ++++++--- Tinke/VisorHex.Designer.cs | 9 +- Tinke/VisorHex.cs | 161 +++++++++++++----- changelog.txt | 6 +- 5 files changed, 206 insertions(+), 71 deletions(-) diff --git a/Be.Windows.Forms.HexBox/ByteCharConverters.cs b/Be.Windows.Forms.HexBox/ByteCharConverters.cs index 6c488a9..1210802 100644 --- a/Be.Windows.Forms.HexBox/ByteCharConverters.cs +++ b/Be.Windows.Forms.HexBox/ByteCharConverters.cs @@ -21,7 +21,9 @@ namespace Be.Windows.Forms /// /// /// - byte ToByte(char c); + byte[] ToByte(char c); + + Encoding ToEncoding(); } /// @@ -44,9 +46,11 @@ namespace Be.Windows.Forms /// /// /// - public virtual byte ToByte(char c) + public virtual byte[] ToByte(char c) { - return (byte)c; + byte[] bytes = new byte[1]; + bytes[0] = (byte)c; + return bytes; } /// @@ -57,6 +61,11 @@ namespace Be.Windows.Forms { return "ANSI (Default)"; } + + public Encoding ToEncoding() + { + return Encoding.Default; + } } /// @@ -86,10 +95,10 @@ namespace Be.Windows.Forms /// /// /// - public virtual byte ToByte(char c) + public virtual byte[] ToByte(char c) { byte[] decoded = _ebcdicEncoding.GetBytes(new char[] { c }); - return decoded.Length > 0 ? decoded[0] : (byte)0; + return decoded.Length > 0 ? decoded : (new byte[1] { 0 }); } /// @@ -100,5 +109,10 @@ namespace Be.Windows.Forms { return "EBCDIC (Code Page 500)"; } + + public Encoding ToEncoding() + { + return this._ebcdicEncoding; + } } } diff --git a/Be.Windows.Forms.HexBox/HexBox.cs b/Be.Windows.Forms.HexBox/HexBox.cs index 7b6480c..56d0eb6 100644 --- a/Be.Windows.Forms.HexBox/HexBox.cs +++ b/Be.Windows.Forms.HexBox/HexBox.cs @@ -1066,11 +1066,13 @@ namespace Be.Windows.Forms _hexBox.ReleaseSelection(); - byte b = _hexBox.ByteCharConverter.ToByte(c); + byte[] b = _hexBox.ByteCharConverter.ToByte(c); if(isInsertMode) - _hexBox._byteProvider.InsertBytes(pos, new byte[]{b}); - else - _hexBox._byteProvider.WriteByte(pos, b); + _hexBox._byteProvider.InsertBytes(pos, b); + else { + foreach (byte bs in b) + _hexBox._byteProvider.WriteByte(pos, bs); + } PerformPosMoveRightByte(); _hexBox.Invalidate(); @@ -1168,15 +1170,15 @@ namespace Be.Windows.Forms /// int _lastThumbtrack; /// - /// Contains the border´s left shift + /// Contains the border left shift /// int _recBorderLeft = SystemInformation.Border3DSize.Width; /// - /// Contains the border´s right shift + /// Contains the border right shift /// int _recBorderRight = SystemInformation.Border3DSize.Width; /// - /// Contains the border´s top shift + /// Contains the border top shift /// int _recBorderTop = SystemInformation.Border3DSize.Height; /// @@ -1807,7 +1809,7 @@ namespace Be.Windows.Forms System.Diagnostics.Debug.WriteLine("UpdateCaret()", "HexBox"); - long byteIndex =_bytePos - _startByte; + long byteIndex = _bytePos - _startByte; PointF p = _keyInterpreter.GetCaretPointF(byteIndex); p.X += _byteCharacterPos*_charSize.Width; NativeMethods.SetCaretPos((int)p.X, (int)p.Y); @@ -2149,7 +2151,8 @@ namespace Be.Windows.Forms DataObject da = new DataObject(); // set string buffer clipbard data - string sBuffer = System.Text.Encoding.ASCII.GetString(buffer, 0, buffer.Length); + Encoding encoding = ByteCharConverter.ToEncoding(); + string sBuffer = encoding.GetString(buffer, 0, buffer.Length); da.SetData(typeof(string), sBuffer); //set memorystream (BinaryData) clipboard data @@ -2229,7 +2232,8 @@ namespace Be.Windows.Forms else if(da.GetDataPresent(typeof(string))) { string sBuffer = (string)da.GetData(typeof(string)); - buffer = System.Text.Encoding.ASCII.GetBytes(sBuffer); + Encoding encoding = ByteCharConverter.ToEncoding(); + buffer = encoding.GetBytes(sBuffer); } else { @@ -2581,9 +2585,37 @@ namespace Be.Windows.Forms g.DrawString(sB.Substring(1,1), Font, brush, bytePointF, _stringFormat); } - void PaintHexAndStringView(Graphics g, long startByte, long endByte) + static bool IsCjkCharacter(char ch) + { + int codePoint = ch; + + // CJK Unified Ideographs + if (codePoint >= 0x4E00 && codePoint <= 0x9FFF) + return true; + + // CJK Unified Ideographs Extension A + if (codePoint >= 0x3400 && codePoint <= 0x4DBF) + return true; + + // CJK Compatibility Ideographs + if (codePoint >= 0xF900 && codePoint <= 0xFAFF) + return true; + + // Additional ranges for CJK (surrogate pairs) + // Note: Surrogate pairs are required for characters beyond U+FFFF + if (char.IsHighSurrogate(ch) || char.IsLowSurrogate(ch)) + { + // Handle surrogate pairs + return false; + } + + return false; + } + + void PaintHexAndStringView(Graphics g, long startByte, long endByte) { - Brush brush = new SolidBrush(GetDefaultForeColor()); + System.Diagnostics.Debug.WriteLine(ByteCharConverter.ToString(), "PaintHexAndStringView()", "HexBox"); + Brush brush = new SolidBrush(GetDefaultForeColor()); Brush selBrush = new SolidBrush(_selectionForeColor); Brush selBrushBack = new SolidBrush(_selectionBackColor); @@ -2612,18 +2644,23 @@ namespace Be.Windows.Forms } string s = new String(ByteCharConverter.ToChar(b), 1); + float cjk_ofs = 0; + if (IsCjkCharacter(s.ToCharArray()[0])) + cjk_ofs = _charSize.Width / 2; - if(isSelectedByte && isStringKeyInterpreterActive) + if (isSelectedByte && isStringKeyInterpreterActive) { - g.FillRectangle(selBrushBack, byteStringPointF.X, byteStringPointF.Y, _charSize.Width, _charSize.Height); - g.DrawString(s, Font, selBrush, byteStringPointF, _stringFormat); + g.FillRectangle(selBrushBack, byteStringPointF.X, byteStringPointF.Y, _charSize.Width, _charSize.Height); + byteStringPointF.X -= cjk_ofs; + g.DrawString(s, Font, selBrush, byteStringPointF, _stringFormat); } else { - g.DrawString(s, Font, brush, byteStringPointF, _stringFormat); + byteStringPointF.X -= cjk_ofs; + g.DrawString(s, Font, brush, byteStringPointF, _stringFormat); } } - } + } void PaintCurrentBytesSign(Graphics g) { @@ -2818,7 +2855,7 @@ namespace Be.Windows.Forms return; _startByte = (_scrollVpos+1) * _iHexMaxHBytes - _iHexMaxHBytes; - _endByte = (long)Math.Min(_byteProvider.Length - 1, _startByte + _iHexMaxBytes); + _endByte = (long)Math.Min(_byteProvider.Length - 1, _startByte + _iHexMaxBytes); } #endregion @@ -3318,9 +3355,9 @@ namespace Be.Windows.Forms } long _lineInfoOffset = 0; /// - /// Gets or sets the hex box´s border style. + /// Gets or sets the hex box border style. /// - [DefaultValue(typeof(BorderStyle), "Fixed3D"), Category("Hex"), Description("Gets or sets the hex box´s border style.")] + [DefaultValue(typeof(BorderStyle), "Fixed3D"), Category("Hex"), Description("Gets or sets the hex box border style.")] public BorderStyle BorderStyle { get { return _borderStyle;} diff --git a/Tinke/VisorHex.Designer.cs b/Tinke/VisorHex.Designer.cs index 3e67531..ef9ea60 100644 --- a/Tinke/VisorHex.Designer.cs +++ b/Tinke/VisorHex.Designer.cs @@ -93,7 +93,7 @@ namespace Tinke this.hexBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.hexBox1.Font = new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.hexBox1.Font = new System.Drawing.Font("Arial", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.hexBox1.InfoForeColor = System.Drawing.Color.Empty; this.hexBox1.LineInfoVisible = true; this.hexBox1.Location = new System.Drawing.Point(0, 24); @@ -301,10 +301,13 @@ namespace Tinke this.encodingCombo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.encodingCombo.Items.AddRange(new object[] { "S0D", + "EBCDIC(CP500)", "Shift_JIS", - "UTF-7", + "UTF-16LE", + "UTF-16BE", "UTF-8", - "ASCII"}); + "ASCII", + "GBK"}); this.encodingCombo.Name = "encodingCombo"; this.encodingCombo.Size = new System.Drawing.Size(120, 25); this.encodingCombo.DropDownClosed += new System.EventHandler(this.encodingCombo_DropDownClosed); diff --git a/Tinke/VisorHex.cs b/Tinke/VisorHex.cs index aeed5c9..cb79a84 100644 --- a/Tinke/VisorHex.cs +++ b/Tinke/VisorHex.cs @@ -145,17 +145,18 @@ namespace Tinke { hexBox1.Height = this.Height - 83; - tableGrid.Width = this.Width - 652; + tableGrid.Width = this.Width - 750; if (tableGrid.Visible) hexBox1.Width = this.Width - (tableGrid.Width + 15); else hexBox1.Width = this.Width - 16; - } private void comboBoxEncoding_SelectedIndexChanged(object sender, EventArgs e) { if (encodingCombo.SelectedIndex == 0) bcc = new DefaultByteCharConverter(); + else if (encodingCombo.SelectedIndex == 1) + bcc = new EbcdicByteCharProvider(); else bcc = new ByteCharConveter(encodingCombo.Text); @@ -290,11 +291,12 @@ namespace Tinke { hexBox1.Width = this.Width - (tableGrid.Width + 15); tableGrid.Show(); + VisorHex_Resize(null, null); } private void tableGrid_CellEndEdit(object sender, DataGridViewCellEventArgs e) { - List codes = new List(); + List codes = new List(); List charas = new List(); for (int i = 0; i < tableGrid.RowCount; i++) @@ -303,7 +305,7 @@ namespace Tinke !(tableGrid.Rows[i].Cells[1].Value is object)) continue; - codes.Add(Convert.ToUInt64((string)tableGrid.Rows[i].Cells[0].Value, 16)); + codes.Add(Convert.ToByte((string)tableGrid.Rows[i].Cells[0].Value, 16)); charas.Add(Convert.ToChar(tableGrid.Rows[i].Cells[1].Value)); } hexBox1.ByteCharConverter = new ByteCharTable(codes.ToArray(), charas.ToArray()); @@ -353,13 +355,10 @@ namespace Tinke for (int i = 0; i < lines.Length; i++) { int sign_pos = lines[i].IndexOf('='); - ushort code = Convert.ToUInt16(lines[i].Substring(0, sign_pos), 16); + byte code = Convert.ToByte(lines[i].Substring(0, sign_pos), 16); char chara = lines[i].Substring(sign_pos + 1)[0]; - if (code <= 0x7E) - tableGrid.Rows.Add(code.ToString("x").ToUpper(), chara); - else - tableGrid.Rows.Add(code.ToString("x").ToUpper().PadLeft(4, '0'), chara); + tableGrid.Rows.Add(code.ToString(), chara); } tableGrid_CellEndEdit(null, null); @@ -465,29 +464,29 @@ namespace Tinke public class ByteCharTable : IByteCharConverter { - Dictionary tableChar; - Dictionary tableByte; + Dictionary tableChar; + Dictionary tableByte; public ByteCharTable(string tablePath) { - tableChar = new Dictionary(); - tableByte = new Dictionary(); + tableChar = new Dictionary(); + tableByte = new Dictionary(); String[] lines = File.ReadAllLines(tablePath); for (int i = 0; i < lines.Length; i++) { int sign_pos = lines[i].IndexOf('='); - ulong code = Convert.ToUInt64(lines[i].Substring(0, sign_pos), 16); + byte code = Convert.ToByte(lines[i].Substring(0, sign_pos), 16); char chara = lines[i].Substring(sign_pos + 1)[0]; tableChar.Add(code, chara); tableByte.Add(chara, code); } } - public ByteCharTable(ulong[] codes, char[] charas) + public ByteCharTable(byte[] codes, char[] charas) { - tableByte = new Dictionary(); - tableChar = new Dictionary(); + tableByte = new Dictionary(); + tableChar = new Dictionary(); for (int i = 0; i < codes.Length; i++) { @@ -505,58 +504,136 @@ namespace Tinke else return '.'; } - public byte ToByte(char c) + public byte[] ToByte(char c) { + byte[] bytes = new byte[1]; if (tableByte.ContainsKey(c)) - return (byte)tableByte[c]; + { + bytes[0] = tableByte[c]; + return bytes; + } else - return 0; + return (new byte[1] { 0 }); + } + public Encoding ToEncoding() + { + return Encoding.Default; } } public class ByteCharConveter : IByteCharConverter { Encoding encoding; - List requeridedChar; - List requeridedByte; + List requiredChar; + List requiredByte; public ByteCharConveter(string encoding) { this.encoding = Encoding.GetEncoding(encoding); - requeridedChar = new List(); - requeridedByte = new List(); + requiredChar = new List(); + requiredByte = new List(); } - public byte ToByte(char c) + public byte[] ToByte(char c) { - if (encoding.WebName == "shift_jis") - return ToByteShiftJis(c); - - return (byte)c; + byte[] decoded = encoding.GetBytes(new char[] { c }); + return decoded.Length > 0 ? decoded : (new byte[1] { 0 }); } public char ToChar(byte b) { - if (encoding.WebName == "shift_jis") - return ToCharShiftJis(b); + if (encoding.WebName == "shift_jis" || encoding.WebName == "gb2312") + return ToCharShiftJisOrGBK(b); + if (encoding.WebName == "utf-8") + return ToCharUtf8(b); + if (encoding.WebName == "utf-16") + return ToCharUtf16Le(b); + if (encoding.WebName == "utf-16BE") + return ToCharUtf16Be(b); return encoding.GetChars(new byte[] { b })[0]; } - public byte ToByteShiftJis(char c) + public char ToCharShiftJisOrGBK(byte b) { - return (byte)c; - } - public char ToCharShiftJis(byte b) - { - if (requeridedChar.Count == 0 && b > 0x7F) + if (requiredChar.Count == 0 && b > 0x7F) { - requeridedChar.Add(b); + requiredChar.Add(b); return '\x20'; } - requeridedChar.Add(b); - string c = new String(encoding.GetChars(requeridedChar.ToArray())); - requeridedChar.Clear(); + requiredChar.Add(b); + string c = new String(encoding.GetChars(requiredChar.ToArray())); + requiredChar.Clear(); return (c[0] > '\x1F' ? c[0] : '.'); } + + public char ToCharUtf16Le(byte b) + { + requiredChar.Add(b); + + if (requiredChar.Count == 2) + { + char c = BitConverter.ToChar(requiredChar.ToArray(), 0); + requiredChar.Clear(); + return (c > '\x1F' ? c : '.'); + } + + return '\x20'; + } + + public char ToCharUtf16Be(byte b) + { + requiredChar.Add(b); + + if (requiredChar.Count == 2) + { + byte[] bytes = requiredChar.ToArray(); + Array.Reverse(bytes); + char c = BitConverter.ToChar(bytes, 0); + requiredChar.Clear(); + return (c > '\x1F' ? c : '.'); + } + + return '\x20'; + } + + public char ToCharUtf8(byte b) + { + if (requiredChar.Count == 0 && !((b & 0x80) == 0)) + { + requiredChar.Add(b); + return '\x20'; + } + else if (requiredChar.Count == 1 && !((requiredChar[0] & 0xE0) == 0xC0)) + { + requiredChar.Add(b); + return '\x20'; + } + else if (requiredChar.Count == 2 && !((requiredChar[0] & 0xF0) == 0xE0)) + { + requiredChar.Add(b); + return '\x20'; + } + + requiredChar.Add(b); + string c = new String(encoding.GetChars(requiredChar.ToArray())); + requiredChar.Clear(); + return (c[0] > '\x1F' ? c[0] : '.'); + } + + public override string ToString() + { + if (encoding.WebName == "utf-16" || encoding.WebName == "utf-16BE") + { + requiredChar.Clear(); + return "Unicode"; + } + return encoding.WebName; + } + + public Encoding ToEncoding() + { + return this.encoding; + } } -} \ No newline at end of file + +} diff --git a/changelog.txt b/changelog.txt index ae720ff..1894e9c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -5,7 +5,7 @@ TinkeDSi 0.9.5 (Made by R-YaTian) * Set Topmost for waiting window, add "Please wait..." message * Special fix for Sonic Classic Collection * Allow drop files to open -* WIP: Improve Hex Editor +* Improve Hex Editor * NFTR plugins: Disable zoom when more than 7489 chars, will fix scrolling issue * Add toolkit: get header crc32 for r4cce/TTdT * Allow copy info to Clipboard by mouse double click on RomInfo window @@ -19,6 +19,10 @@ TinkeDSi 0.9.5 (Made by R-YaTian) * 3DModels: Update to OpenTK 3.3.3, fix bug on fullscreen btn * Improved SF Feather Plugin (By @mn1712trungson) * Core: Improve Nitrocode check when saving rom +* Saveoptions: Add an option to "Recompress ARM9 binary" +* Saveoptions: Add an option to parse the header of flashcart firmware +* Implement command line support +* Update Be.Windows.Forms.HexBox to 1.6.0 TODO: full i18n support (include plugins) TinkeDSi 0.9.4