From f1042ba7d6709452e76c29e2a245342d09eeb066 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Thu, 8 Oct 2026 12:36:02 +0900 Subject: [PATCH 1/2] chore: enable the Kotlin Lombok compiler plugin Kotlin sources compile before javac runs Lombok, so Kotlin code cannot see Lombok-generated members such as Range.of from @Value(staticConstructor). Earlier ports had to work around this, and the RawTextPane port needs a Range instance. The plugin lets Kotlin resolve those members, so Java classes stay as they are while more of the codebase moves to Kotlin. The plugin is still experimental in Kotlin 2.2 and prints a warning on every Kotlin compile. Its version follows the Kotlin JVM plugin. Co-authored-by: Cursor --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 87f7b2cc..d45c3ee8 100644 --- a/build.gradle +++ b/build.gradle @@ -18,6 +18,7 @@ plugins { id "de.undercouch.download" version "5.6.0" id "com.diffplug.spotless" version "7.1.0" id 'org.jetbrains.kotlin.jvm' version '2.2.21' + id 'org.jetbrains.kotlin.plugin.lombok' version '2.2.21' } repositories { From 520e2585ab9faf809894f0c7dc6e86e8c4734058 Mon Sep 17 00:00:00 2001 From: Hiroki Tokunaga Date: Thu, 8 Oct 2026 12:36:07 +0900 Subject: [PATCH 2/2] refactor: port RawTextPane to Kotlin Co-authored-by: Cursor --- .../core/packetproxy/gui/RawTextPane.java | 469 ------------------ .../core/packetproxy/gui/RawTextPane.kt | 449 +++++++++++++++++ 2 files changed, 449 insertions(+), 469 deletions(-) delete mode 100644 src/main/java/core/packetproxy/gui/RawTextPane.java create mode 100644 src/main/kotlin/core/packetproxy/gui/RawTextPane.kt diff --git a/src/main/java/core/packetproxy/gui/RawTextPane.java b/src/main/java/core/packetproxy/gui/RawTextPane.java deleted file mode 100644 index fa7cac9d..00000000 --- a/src/main/java/core/packetproxy/gui/RawTextPane.java +++ /dev/null @@ -1,469 +0,0 @@ -/* - * Copyright 2019 DeNA Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package packetproxy.gui; - -import static packetproxy.util.Logging.errWithStackTrace; - -import java.awt.Color; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.util.Arrays; -import java.util.Base64; -import javax.swing.JMenuItem; -import javax.swing.JPopupMenu; -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.StringEscapeUtils; -import org.apache.commons.lang3.StringUtils; -import packetproxy.VulCheckerManager; -import packetproxy.common.FontManager; -import packetproxy.common.I18nString; -import packetproxy.common.Range; -import packetproxy.common.Utils; -import packetproxy.model.Packet; -import packetproxy.util.CharSetUtility; -import packetproxy.vulchecker.VulChecker; - -public class RawTextPane extends ExtendedTextPane { - - private CharSetUtility charSetUtility; - - public RawTextPane() throws Exception { - charSetUtility = CharSetUtility.getInstance(); - - JPopupMenu menu = new JPopupMenu(); - - addKeyListener(new KeyAdapter() { - - public void keyPressed(KeyEvent e) { - switch (e.getKeyCode()) { - case KeyEvent.VK_Z : - if ((Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() & e.getModifiers()) > 0) { - /* Command key */ - - if (e.isShiftDown()) { - /* Ctrl-Shift-Z */ - - if (undo_manager.canRedo()) - undo_manager.redo(); - } else { - /* Ctrl-Z */ - - if (undo_manager.canUndo()) - undo_manager.undo(); - } - e.consume(); - } - break; - case KeyEvent.VK_Y : - if ((Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() & e.getModifiers()) > 0) { - /* Command key */ - - if (undo_manager.canRedo()) - /* Ctrl-Y */ undo_manager.redo(); - e.consume(); - } - break; - } - } - }); - - JMenuItem vulCheckers = new JMenuItem(I18nString.get("VulCheck Helpers")); - vulCheckers.setFont(FontManager.getInstance().getUICaptionFont()); - vulCheckers.setEnabled(false); - menu.add(vulCheckers); - - for (String vulCheckerName : VulCheckerManager.getInstance().getAllVulCheckers().keySet()) { - - VulChecker vulChecker = VulCheckerManager.getInstance().createInstance(vulCheckerName); - JMenuItem vulCheckerItem = new JMenuItem(vulChecker.getName()); - vulCheckerItem.addActionListener(actionEvent -> { - try { - - Range range = Range.of(getSelectionStart(), getSelectionEnd()); - Packet packet = GUIPacket.getInstance().getPacket(); - GUIVulCheckHelper.getInstance().addVulCheck(vulChecker, packet.getOneShotPacket(getData()), range); - } catch (Exception e) { - - errWithStackTrace(e); - } - }); - menu.add(vulCheckerItem); - } - - menu.addSeparator(); - JMenuItem title_decoders = new JMenuItem(I18nString.get("Decoders")); - title_decoders.setFont(FontManager.getInstance().getUICaptionFont()); - title_decoders.setEnabled(false); - menu.add(title_decoders); - - JMenuItem url_decoder = new JMenuItem("URL Decoder"); - url_decoder.addActionListener(new ActionListener() { - - public void actionPerformed(ActionEvent actionEvent) { - try { - - if (charSetUtility.isAuto()) { - - charSetUtility.setGuessedCharSet(getData()); - } - String chasetName = charSetUtility.getCharSet(); - int position_start = getSelectionStart(); - int position_end = getSelectionEnd(); - byte[] data = new String(getData(), chasetName).substring(position_start, position_end).getBytes(); - GUIDecoderDialog dlg = new GUIDecoderDialog(); - dlg.setData(URLDecoder.decode(new String(data), chasetName).getBytes()); - dlg.showDialog(); - } catch (Exception e) { - - errWithStackTrace(e); - } - } - }); - menu.add(url_decoder); - - JMenuItem base64_decoder = new JMenuItem("Base64 / Base64url Decoder"); - base64_decoder.addActionListener(new ActionListener() { - - public void actionPerformed(ActionEvent actionEvent) { - try { - - int position_start = getSelectionStart(); - int position_end = getSelectionEnd(); - - if (charSetUtility.isAuto()) { - - charSetUtility.setGuessedCharSet(getData()); - } - byte[] data = new String(getData(), charSetUtility.getCharSet()) - .substring(position_start, position_end).getBytes(); - GUIDecoderDialog dlg = new GUIDecoderDialog(); - if (Utils.indexOf(data, 0, data.length, "_".getBytes()) >= 0 - || Utils.indexOf(data, 0, data.length, "-".getBytes()) >= 0) { // base64url - - dlg.setData(Base64.getUrlDecoder().decode(data)); - } else { // base64 - - dlg.setData(Base64.getDecoder().decode(data)); - } - dlg.showDialog(); - } catch (Exception e) { - - errWithStackTrace(e); - } - } - }); - menu.add(base64_decoder); - - JMenuItem jwt_decoder = new JMenuItem("JWT Decoder"); - jwt_decoder.addActionListener(new ActionListener() { - - public void actionPerformed(ActionEvent actionEvent) { - try { - - if (charSetUtility.isAuto()) { - - charSetUtility.setGuessedCharSet(getData()); - } - String charSetName = charSetUtility.getCharSet(); - int position_start = getSelectionStart(); - int position_end = getSelectionEnd(); - byte[] data = new String(getData(), charSetName).substring(position_start, position_end).getBytes(); - GUIDecoderDialog dlg = new GUIDecoderDialog(); - dlg.setData(Arrays.stream(new String(data, charSetName).split("\\.")) - .map(Base64.getUrlDecoder()::decode).reduce((a, b) -> { - return ArrayUtils.addAll(ArrayUtils.addAll(a, ".".getBytes()), b); - }).get()); - dlg.showDialog(); - } catch (Exception e) { - - errWithStackTrace(e); - } - } - }); - menu.add(jwt_decoder); - - JMenuItem unicode_unescaper = new JMenuItem("Unicode Unescaper"); - unicode_unescaper.addActionListener(new ActionListener() { - - public void actionPerformed(ActionEvent actionEvent) { - try { - - if (charSetUtility.isAuto()) { - - charSetUtility.setGuessedCharSet(getData()); - } - String charSetName = charSetUtility.getCharSet(); - int position_start = getSelectionStart(); - int position_end = getSelectionEnd(); - byte[] data = new String(getData(), charSetName).substring(position_start, position_end).getBytes(); - String selection = new String(data, charSetName); - String unescaped = StringEscapeUtils.unescapeJava(selection); - GUIDecoderDialog dlg = new GUIDecoderDialog(); - dlg.setData(unescaped.getBytes()); - dlg.showDialog(); - } catch (Exception e) { - - errWithStackTrace(e); - } - } - }); - menu.add(unicode_unescaper); - - menu.addSeparator(); - JMenuItem title_encoders = new JMenuItem(I18nString.get("Encoders")); - title_encoders.setFont(FontManager.getInstance().getUICaptionFont()); - title_encoders.setEnabled(false); - menu.add(title_encoders); - - JMenuItem url_encoder = new JMenuItem("URL Encoder"); - url_encoder.addActionListener(new ActionListener() { - - public void actionPerformed(ActionEvent actionEvent) { - try { - - if (charSetUtility.isAuto()) { - - charSetUtility.setGuessedCharSet(getData()); - } - String charSetName = charSetUtility.getCharSet(); - int position_start = getSelectionStart(); - int position_end = getSelectionEnd(); - byte[] data = new String(getData(), charSetName).substring(position_start, position_end).getBytes(); - GUIDecoderDialog dlg = new GUIDecoderDialog(); - dlg.setData(URLEncoder.encode(new String(data), charSetName).getBytes()); - dlg.showDialog(); - } catch (Exception e) { - - errWithStackTrace(e); - } - } - }); - menu.add(url_encoder); - - JMenuItem base64_encoder = new JMenuItem("Base64 Encoder"); - base64_encoder.addActionListener(new ActionListener() { - - public void actionPerformed(ActionEvent actionEvent) { - try { - - if (charSetUtility.isAuto()) { - - charSetUtility.setGuessedCharSet(getData()); - } - String charSetName = charSetUtility.getCharSet(); - int position_start = getSelectionStart(); - int position_end = getSelectionEnd(); - byte[] data = new String(getData(), charSetName).substring(position_start, position_end).getBytes(); - GUIDecoderDialog dlg = new GUIDecoderDialog(); - dlg.setData(Base64.getEncoder().encode(data)); - dlg.showDialog(); - } catch (Exception e) { - - errWithStackTrace(e); - } - } - }); - menu.add(base64_encoder); - - JMenuItem base64url_encoder = new JMenuItem("Base64url Encoder"); - base64url_encoder.addActionListener(new ActionListener() { - - public void actionPerformed(ActionEvent actionEvent) { - try { - - if (charSetUtility.isAuto()) { - - charSetUtility.setGuessedCharSet(getData()); - } - String charSetName = charSetUtility.getCharSet(); - int position_start = getSelectionStart(); - int position_end = getSelectionEnd(); - byte[] data = new String(getData(), charSetName).substring(position_start, position_end).getBytes(); - GUIDecoderDialog dlg = new GUIDecoderDialog(); - dlg.setData(Base64.getUrlEncoder().encode(data)); - dlg.showDialog(); - } catch (Exception e) { - - errWithStackTrace(e); - } - } - }); - menu.add(base64url_encoder); - - JMenuItem jwt_encoder = new JMenuItem("JWT Encoder"); - jwt_encoder.addActionListener(new ActionListener() { - - public void actionPerformed(ActionEvent actionEvent) { - try { - - if (charSetUtility.isAuto()) { - - charSetUtility.setGuessedCharSet(getData()); - } - String charSetName = charSetUtility.getCharSet(); - int position_start = getSelectionStart(); - int position_end = getSelectionEnd(); - byte[] data = new String(getData(), charSetName).substring(position_start, position_end).getBytes(); - GUIDecoderDialog dlg = new GUIDecoderDialog(); - dlg.setData(Arrays.stream(new String(data, charSetName).split("\\.")).map((a) -> { - String b = ""; - if (a.charAt(0) == '{') { - - b = new String(Base64.getUrlEncoder().encode(a.getBytes())); - } else { - /* signature */ - - b = new String(Base64.getUrlEncoder() - .encode("12345678901234567890123456789012".getBytes())); /* return 32 bytes data */ - } - return StringUtils.strip(b, "=").getBytes(); - }).reduce((a, b) -> { - return ArrayUtils.addAll(ArrayUtils.addAll(a, ".".getBytes()), b); - }).get()); - dlg.showDialog(); - } catch (Exception e) { - - errWithStackTrace(e); - } - } - }); - menu.add(jwt_encoder); - - JMenuItem unicode_escaper = new JMenuItem("Unicode Escaper"); - unicode_escaper.addActionListener(new ActionListener() { - - public void actionPerformed(ActionEvent actionEvent) { - try { - - if (charSetUtility.isAuto()) { - - charSetUtility.setGuessedCharSet(getData()); - } - String charSetName = charSetUtility.getCharSet(); - int position_start = getSelectionStart(); - int position_end = getSelectionEnd(); - String selection = new String(getData(), charSetName).substring(position_start, position_end); - StringBuilder sb = new StringBuilder(); - for (char c : selection.toCharArray()) { - - sb.append(String.format("\\u%04X", (int) c)); - } - String unicode = sb.toString(); - GUIDecoderDialog dlg = new GUIDecoderDialog(); - dlg.setData(unicode.getBytes()); - dlg.showDialog(); - } catch (Exception e) { - - errWithStackTrace(e); - } - } - }); - menu.add(unicode_escaper); - - addMouseListener(new MouseAdapter() { - - @Override - public void mouseReleased(MouseEvent event) { - if (Utils.isWindows() && event.isPopupTrigger()) { - - menu.show(event.getComponent(), event.getX(), event.getY()); - } - } - - @Override - public void mousePressed(MouseEvent event) { - if (event.isPopupTrigger()) { - - menu.show(event.getComponent(), event.getX(), event.getY()); - } - } - }); - } - - @Override - protected String prepareTextForCopy(String selected) { - return stripTrailingNewlines(selected); - } - - @Override - public void setEditable(boolean b) { - super.setEditable(b); - if (!b) { - this.setBackground(Color.WHITE); - } - } - - public void setData(byte[] data) throws Exception { - init_flg = true; - fin_flg = true; - init_count = 0; - prev_text_panel = ""; - raw_data.reset(data); - if (charSetUtility.isAuto()) { - - charSetUtility.setGuessedCharSet(getData()); - } - String charSetName = charSetUtility.getCharSet(); - setText(new String(data, charSetName)); - undo_manager.discardAllEdits(); - } - - public byte[] getData() { - return raw_data.toByteArray(); - } - - /* バイナリデータだとデータが壊れるので要注意 */ - public String getText() { - return new String(raw_data.toByteArray()); - } - - /* バイナリデータだとデータが壊れるので要注意 */ - public void setText(String text) { - try { - - fin_flg = true; - init_flg = true; - init_count = 0; - prev_text_panel = ""; - raw_data.reset(text.getBytes()); - super.setText(text); - undo_manager.discardAllEdits(); - } catch (Exception e) { - - errWithStackTrace(e); - } - } - - private static String stripTrailingNewlines(String s) { - int end = s.length(); - while (end > 0) { - char c = s.charAt(end - 1); - if (c == '\n' || c == '\r') { - end--; - continue; - } - break; - } - return end == s.length() ? s : s.substring(0, end); - } -} diff --git a/src/main/kotlin/core/packetproxy/gui/RawTextPane.kt b/src/main/kotlin/core/packetproxy/gui/RawTextPane.kt new file mode 100644 index 00000000..6ac75744 --- /dev/null +++ b/src/main/kotlin/core/packetproxy/gui/RawTextPane.kt @@ -0,0 +1,449 @@ +/* + * Copyright 2026 DeNA Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package packetproxy.gui + +import java.awt.Color +import java.awt.Toolkit +import java.awt.event.KeyAdapter +import java.awt.event.KeyEvent +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent +import java.net.URLDecoder +import java.net.URLEncoder +import java.nio.charset.Charset +import java.util.Arrays +import java.util.Base64 +import javax.swing.JMenuItem +import javax.swing.JPopupMenu +import org.apache.commons.lang3.ArrayUtils +import org.apache.commons.lang3.StringEscapeUtils +import org.apache.commons.lang3.StringUtils +import packetproxy.VulCheckerManager +import packetproxy.common.FontManager +import packetproxy.common.I18nString +import packetproxy.common.Range +import packetproxy.common.Utils +import packetproxy.util.CharSetUtility +import packetproxy.util.Logging.errWithStackTrace + +internal open class RawTextPane @Throws(Exception::class) constructor() : ExtendedTextPane() { + + private val charSetUtility: CharSetUtility = CharSetUtility.getInstance() + + init { + val menu = JPopupMenu() + + addKeyListener( + object : KeyAdapter() { + @Suppress("DEPRECATION") + override fun keyPressed(e: KeyEvent) { + when (e.keyCode) { + KeyEvent.VK_Z -> { + if ((Toolkit.getDefaultToolkit().menuShortcutKeyMask and e.modifiers) > 0) { + /* Command key */ + + if (e.isShiftDown) { + /* Ctrl-Shift-Z */ + + if (undo_manager.canRedo()) undo_manager.redo() + } else { + /* Ctrl-Z */ + + if (undo_manager.canUndo()) undo_manager.undo() + } + e.consume() + } + } + KeyEvent.VK_Y -> { + if ((Toolkit.getDefaultToolkit().menuShortcutKeyMask and e.modifiers) > 0) { + /* Command key */ + + if (undo_manager.canRedo()) /* Ctrl-Y */ undo_manager.redo() + e.consume() + } + } + } + } + } + ) + + val vulCheckers = JMenuItem(I18nString.get("VulCheck Helpers")) + vulCheckers.font = FontManager.getInstance().uiCaptionFont + vulCheckers.isEnabled = false + menu.add(vulCheckers) + + for (vulCheckerName in VulCheckerManager.getInstance().allVulCheckers.keys) { + val vulChecker = VulCheckerManager.getInstance().createInstance(vulCheckerName) + val vulCheckerItem = JMenuItem(vulChecker.name) + vulCheckerItem.addActionListener { + try { + val range = Range.of(selectionStart, selectionEnd) + val packet = GUIPacket.getInstance().packet + GUIVulCheckHelper.getInstance() + .addVulCheck(vulChecker, packet.getOneShotPacket(getData()), range) + } catch (e: Exception) { + errWithStackTrace(e) + } + } + menu.add(vulCheckerItem) + } + + menu.addSeparator() + val title_decoders = JMenuItem(I18nString.get("Decoders")) + title_decoders.font = FontManager.getInstance().uiCaptionFont + title_decoders.isEnabled = false + menu.add(title_decoders) + + val url_decoder = JMenuItem("URL Decoder") + url_decoder.addActionListener { + try { + if (charSetUtility.isAuto) { + charSetUtility.setGuessedCharSet(getData()) + } + val chasetName = charSetUtility.charSet + val position_start = selectionStart + val position_end = selectionEnd + val data = + String(getData(), charset(chasetName)) + .substring(position_start, position_end) + .toByteArray(Charset.defaultCharset()) + val dlg = GUIDecoderDialog() + dlg.setData( + URLDecoder.decode(String(data, Charset.defaultCharset()), chasetName) + .toByteArray(Charset.defaultCharset()) + ) + dlg.showDialog() + } catch (e: Exception) { + errWithStackTrace(e) + } + } + menu.add(url_decoder) + + val base64_decoder = JMenuItem("Base64 / Base64url Decoder") + base64_decoder.addActionListener { + try { + val position_start = selectionStart + val position_end = selectionEnd + + if (charSetUtility.isAuto) { + charSetUtility.setGuessedCharSet(getData()) + } + val data = + String(getData(), charset(charSetUtility.charSet)) + .substring(position_start, position_end) + .toByteArray(Charset.defaultCharset()) + val dlg = GUIDecoderDialog() + if ( + Utils.indexOf(data, 0, data.size, "_".toByteArray(Charset.defaultCharset())) >= 0 || + Utils.indexOf(data, 0, data.size, "-".toByteArray(Charset.defaultCharset())) >= 0 + ) { // base64url + dlg.setData(Base64.getUrlDecoder().decode(data)) + } else { // base64 + dlg.setData(Base64.getDecoder().decode(data)) + } + dlg.showDialog() + } catch (e: Exception) { + errWithStackTrace(e) + } + } + menu.add(base64_decoder) + + val jwt_decoder = JMenuItem("JWT Decoder") + jwt_decoder.addActionListener { + try { + if (charSetUtility.isAuto) { + charSetUtility.setGuessedCharSet(getData()) + } + val charSetName = charSetUtility.charSet + val position_start = selectionStart + val position_end = selectionEnd + val data = + String(getData(), charset(charSetName)) + .substring(position_start, position_end) + .toByteArray(Charset.defaultCharset()) + val dlg = GUIDecoderDialog() + dlg.setData( + Arrays.stream("\\.".toPattern().split(String(data, charset(charSetName)))) + .map(Base64.getUrlDecoder()::decode) + .reduce { a, b -> + ArrayUtils.addAll( + ArrayUtils.addAll(a, *".".toByteArray(Charset.defaultCharset())), + *b, + ) + } + .get() + ) + dlg.showDialog() + } catch (e: Exception) { + errWithStackTrace(e) + } + } + menu.add(jwt_decoder) + + val unicode_unescaper = JMenuItem("Unicode Unescaper") + unicode_unescaper.addActionListener { + try { + if (charSetUtility.isAuto) { + charSetUtility.setGuessedCharSet(getData()) + } + val charSetName = charSetUtility.charSet + val position_start = selectionStart + val position_end = selectionEnd + val data = + String(getData(), charset(charSetName)) + .substring(position_start, position_end) + .toByteArray(Charset.defaultCharset()) + val selection = String(data, charset(charSetName)) + val unescaped = StringEscapeUtils.unescapeJava(selection) + val dlg = GUIDecoderDialog() + dlg.setData(unescaped.toByteArray(Charset.defaultCharset())) + dlg.showDialog() + } catch (e: Exception) { + errWithStackTrace(e) + } + } + menu.add(unicode_unescaper) + + menu.addSeparator() + val title_encoders = JMenuItem(I18nString.get("Encoders")) + title_encoders.font = FontManager.getInstance().uiCaptionFont + title_encoders.isEnabled = false + menu.add(title_encoders) + + val url_encoder = JMenuItem("URL Encoder") + url_encoder.addActionListener { + try { + if (charSetUtility.isAuto) { + charSetUtility.setGuessedCharSet(getData()) + } + val charSetName = charSetUtility.charSet + val position_start = selectionStart + val position_end = selectionEnd + val data = + String(getData(), charset(charSetName)) + .substring(position_start, position_end) + .toByteArray(Charset.defaultCharset()) + val dlg = GUIDecoderDialog() + dlg.setData( + URLEncoder.encode(String(data, Charset.defaultCharset()), charSetName) + .toByteArray(Charset.defaultCharset()) + ) + dlg.showDialog() + } catch (e: Exception) { + errWithStackTrace(e) + } + } + menu.add(url_encoder) + + val base64_encoder = JMenuItem("Base64 Encoder") + base64_encoder.addActionListener { + try { + if (charSetUtility.isAuto) { + charSetUtility.setGuessedCharSet(getData()) + } + val charSetName = charSetUtility.charSet + val position_start = selectionStart + val position_end = selectionEnd + val data = + String(getData(), charset(charSetName)) + .substring(position_start, position_end) + .toByteArray(Charset.defaultCharset()) + val dlg = GUIDecoderDialog() + dlg.setData(Base64.getEncoder().encode(data)) + dlg.showDialog() + } catch (e: Exception) { + errWithStackTrace(e) + } + } + menu.add(base64_encoder) + + val base64url_encoder = JMenuItem("Base64url Encoder") + base64url_encoder.addActionListener { + try { + if (charSetUtility.isAuto) { + charSetUtility.setGuessedCharSet(getData()) + } + val charSetName = charSetUtility.charSet + val position_start = selectionStart + val position_end = selectionEnd + val data = + String(getData(), charset(charSetName)) + .substring(position_start, position_end) + .toByteArray(Charset.defaultCharset()) + val dlg = GUIDecoderDialog() + dlg.setData(Base64.getUrlEncoder().encode(data)) + dlg.showDialog() + } catch (e: Exception) { + errWithStackTrace(e) + } + } + menu.add(base64url_encoder) + + val jwt_encoder = JMenuItem("JWT Encoder") + jwt_encoder.addActionListener { + try { + if (charSetUtility.isAuto) { + charSetUtility.setGuessedCharSet(getData()) + } + val charSetName = charSetUtility.charSet + val position_start = selectionStart + val position_end = selectionEnd + val data = + String(getData(), charset(charSetName)) + .substring(position_start, position_end) + .toByteArray(Charset.defaultCharset()) + val dlg = GUIDecoderDialog() + dlg.setData( + Arrays.stream("\\.".toPattern().split(String(data, charset(charSetName)))) + .map { a -> + val b = + if (a[0] == '{') { + String( + Base64.getUrlEncoder().encode(a.toByteArray(Charset.defaultCharset())), + Charset.defaultCharset(), + ) + } else { + /* signature */ + String( + Base64.getUrlEncoder() + .encode( + "12345678901234567890123456789012".toByteArray(Charset.defaultCharset()) + ), + Charset.defaultCharset(), + ) /* return 32 bytes data */ + } + StringUtils.strip(b, "=").toByteArray(Charset.defaultCharset()) + } + .reduce { a, b -> + ArrayUtils.addAll( + ArrayUtils.addAll(a, *".".toByteArray(Charset.defaultCharset())), + *b, + ) + } + .get() + ) + dlg.showDialog() + } catch (e: Exception) { + errWithStackTrace(e) + } + } + menu.add(jwt_encoder) + + val unicode_escaper = JMenuItem("Unicode Escaper") + unicode_escaper.addActionListener { + try { + if (charSetUtility.isAuto) { + charSetUtility.setGuessedCharSet(getData()) + } + val charSetName = charSetUtility.charSet + val position_start = selectionStart + val position_end = selectionEnd + val selection = + String(getData(), charset(charSetName)).substring(position_start, position_end) + val sb = StringBuilder() + for (c in selection.toCharArray()) { + sb.append(String.format("\\u%04X", c.code)) + } + val unicode = sb.toString() + val dlg = GUIDecoderDialog() + dlg.setData(unicode.toByteArray(Charset.defaultCharset())) + dlg.showDialog() + } catch (e: Exception) { + errWithStackTrace(e) + } + } + menu.add(unicode_escaper) + + addMouseListener( + object : MouseAdapter() { + override fun mouseReleased(event: MouseEvent) { + if (Utils.isWindows() && event.isPopupTrigger) { + menu.show(event.component, event.x, event.y) + } + } + + override fun mousePressed(event: MouseEvent) { + if (event.isPopupTrigger) { + menu.show(event.component, event.x, event.y) + } + } + } + ) + } + + override fun prepareTextForCopy(selected: String): String { + return stripTrailingNewlines(selected) + } + + override fun setEditable(b: Boolean) { + super.setEditable(b) + if (!b) { + background = Color.WHITE + } + } + + @Throws(Exception::class) + override fun setData(data: ByteArray?) { + init_flg = true + fin_flg = true + init_count = 0 + prev_text_panel = "" + raw_data.reset(data) + if (charSetUtility.isAuto) { + charSetUtility.setGuessedCharSet(getData()) + } + val charSetName = charSetUtility.charSet + text = String(data!!, charset(charSetName)) + undo_manager.discardAllEdits() + } + + override fun getData(): ByteArray { + return raw_data.toByteArray() + } + + /* バイナリデータだとデータが壊れるので要注意 */ + override fun getText(): String { + return String(raw_data.toByteArray(), Charset.defaultCharset()) + } + + /* バイナリデータだとデータが壊れるので要注意 */ + override fun setText(text: String?) { + try { + fin_flg = true + init_flg = true + init_count = 0 + prev_text_panel = "" + raw_data.reset(text!!.toByteArray(Charset.defaultCharset())) + super.setText(text) + undo_manager.discardAllEdits() + } catch (e: Exception) { + errWithStackTrace(e) + } + } +} + +private fun stripTrailingNewlines(s: String): String { + var end = s.length + while (end > 0) { + val c = s[end - 1] + if (c == '\n' || c == '\r') { + end-- + continue + } + break + } + return if (end == s.length) s else s.substring(0, end) +}