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 { 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) +}