From 0f5d07c6b14c1a77842feb2c7a9b7032583bb194 Mon Sep 17 00:00:00 2001 From: Mino Date: Mon, 31 Jul 2023 00:02:39 +0100 Subject: [PATCH] feat(gui): hex-viewer for binary asset files (#198)(PR #1969) * implemented hex-viewer feature * added support for opening lib (.so) files * removed unused class * fix formatting * fixed error when opening an empty file * fixed a slight inaccuracy in synchronizing highlights * defaulted little endian to false * synchronize hex editor with theme and use smali font * fixed wrong displayed values * applied code formatting * fixed selection color in preview panel * Changed Smali Editor font entry in settings less confusing --- .../java/jadx/gui/treemodel/JResource.java | 9 +- .../gui/ui/codearea/BinaryContentPanel.java | 99 +++++++++ .../java/jadx/gui/ui/codearea/HexArea.java | 199 ++++++++++++++++++ .../gui/ui/codearea/HexAreaConfiguration.java | 7 + .../ui/codearea/HexConfigurationPanel.java | 139 ++++++++++++ .../jadx/gui/ui/codearea/HexPreviewPanel.java | 94 +++++++++ .../resources/i18n/Messages_de_DE.properties | 2 +- .../resources/i18n/Messages_en_US.properties | 2 +- .../resources/i18n/Messages_ko_KR.properties | 2 +- .../resources/i18n/Messages_pt_BR.properties | 2 +- .../resources/i18n/Messages_ru_RU.properties | 2 +- .../resources/i18n/Messages_zh_CN.properties | 2 +- .../resources/i18n/Messages_zh_TW.properties | 2 +- 13 files changed, 553 insertions(+), 8 deletions(-) create mode 100644 jadx-gui/src/main/java/jadx/gui/ui/codearea/BinaryContentPanel.java create mode 100644 jadx-gui/src/main/java/jadx/gui/ui/codearea/HexArea.java create mode 100644 jadx-gui/src/main/java/jadx/gui/ui/codearea/HexAreaConfiguration.java create mode 100644 jadx-gui/src/main/java/jadx/gui/ui/codearea/HexConfigurationPanel.java create mode 100644 jadx-gui/src/main/java/jadx/gui/ui/codearea/HexPreviewPanel.java diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java index 49047dae5..45da2f71b 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java @@ -21,6 +21,7 @@ import jadx.core.utils.ListUtils; import jadx.core.utils.Utils; import jadx.core.xmlgen.ResContainer; import jadx.gui.ui.TabbedPane; +import jadx.gui.ui.codearea.BinaryContentPanel; import jadx.gui.ui.codearea.CodeContentPanel; import jadx.gui.ui.panel.ContentPanel; import jadx.gui.ui.panel.ImagePanel; @@ -131,6 +132,12 @@ public class JResource extends JLoadableNode { if (resFile.getType() == ResourceType.IMG) { return new ImagePanel(tabbedPane, this); } + if (resFile.getType() == ResourceType.LIB) { + return new BinaryContentPanel(tabbedPane, this, false); + } + if (getSyntaxByExtension(resFile.getDeobfName()) == null) { + return new BinaryContentPanel(tabbedPane, this); + } return new CodeContentPanel(tabbedPane, this); } @@ -272,7 +279,6 @@ public class JResource extends JLoadableNode { switch (type) { case CODE: case FONT: - case LIB: case MEDIA: return false; @@ -280,6 +286,7 @@ public class JResource extends JLoadableNode { case XML: case ARSC: case IMG: + case LIB: case UNKNOWN: return true; } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/BinaryContentPanel.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/BinaryContentPanel.java new file mode 100644 index 000000000..fcdc5fd5a --- /dev/null +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/BinaryContentPanel.java @@ -0,0 +1,99 @@ +package jadx.gui.ui.codearea; + +import java.awt.BorderLayout; +import java.awt.Component; + +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; +import javax.swing.border.EmptyBorder; + +import jadx.gui.settings.JadxSettings; +import jadx.gui.settings.LineNumbersMode; +import jadx.gui.treemodel.JNode; +import jadx.gui.ui.TabbedPane; + +public class BinaryContentPanel extends AbstractCodeContentPanel { + private final transient CodePanel textCodePanel; + private final transient CodePanel hexCodePanel; + private final transient HexConfigurationPanel hexConfigurationPanel; + private final transient JTabbedPane areaTabbedPane; + + public BinaryContentPanel(TabbedPane panel, JNode jnode) { + this(panel, jnode, true); + } + + public BinaryContentPanel(TabbedPane panel, JNode jnode, boolean supportsText) { + super(panel, jnode); + setLayout(new BorderLayout()); + setBorder(new EmptyBorder(0, 0, 0, 0)); + if (supportsText) { + textCodePanel = new CodePanel(new CodeArea(this, jnode)); + } else { + textCodePanel = null; + } + HexArea hexArea = new HexArea(this, jnode); + hexConfigurationPanel = new HexConfigurationPanel(hexArea.getConfiguration()); + hexArea.setConfigurationPanel(hexConfigurationPanel); + hexCodePanel = new CodePanel(hexArea); + areaTabbedPane = buildTabbedPane(); + add(areaTabbedPane); + + getSelectedPanel().load(); + } + + private JTabbedPane buildTabbedPane() { + JSplitPane hexSplitPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, hexCodePanel, hexConfigurationPanel); + hexSplitPanel.setResizeWeight(0.8); + + JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.BOTTOM); + tabbedPane.setBorder(new EmptyBorder(0, 0, 0, 0)); + tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); + if (textCodePanel != null) { + tabbedPane.add(textCodePanel, "Text"); + } + tabbedPane.add(hexSplitPanel, "Hex"); + tabbedPane.addChangeListener(e -> { + getSelectedPanel().load(); + }); + return tabbedPane; + } + + @Override + public AbstractCodeArea getCodeArea() { + if (textCodePanel != null) { + return textCodePanel.getCodeArea(); + } else { + return hexCodePanel.getCodeArea(); + } + } + + @Override + public void loadSettings() { + if (textCodePanel != null) { + textCodePanel.loadSettings(); + } + hexCodePanel.loadSettings(); + updateUI(); + } + + @Override + public JadxSettings getSettings() { + JadxSettings settings = super.getSettings(); + settings.setLineNumbersMode(LineNumbersMode.NORMAL); + return settings; + } + + private CodePanel getSelectedPanel() { + Component selectedComponent = areaTabbedPane.getSelectedComponent(); + CodePanel selectedPanel; + if (selectedComponent instanceof CodePanel) { + selectedPanel = (CodePanel) selectedComponent; + } else if (selectedComponent instanceof JSplitPane) { + selectedPanel = (CodePanel) ((JSplitPane) selectedComponent).getLeftComponent(); + } else { + throw new RuntimeException("tabbedPane.getSelectedComponent returned a Component " + + "of unexpected type " + selectedComponent); + } + return selectedPanel; + } +} diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/HexArea.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/HexArea.java new file mode 100644 index 000000000..b74de56f7 --- /dev/null +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/HexArea.java @@ -0,0 +1,199 @@ +package jadx.gui.ui.codearea; + +import java.awt.BorderLayout; +import java.awt.Font; +import java.nio.charset.StandardCharsets; + +import javax.swing.border.EmptyBorder; +import javax.swing.event.CaretEvent; +import javax.swing.event.CaretListener; + +import org.apache.commons.lang3.StringUtils; +import org.fife.ui.rsyntaxtextarea.Theme; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jadx.api.ICodeInfo; +import jadx.gui.treemodel.JNode; +import jadx.gui.ui.panel.ContentPanel; +import jadx.gui.utils.UiUtils; + +public class HexArea extends AbstractCodeArea { + private static final Logger LOG = LoggerFactory.getLogger(HexArea.class); + + private static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII); + + private final HexAreaConfiguration config; + private final JNode binaryNode; + private final HexPreviewPanel hexPreviewPanel; + private HexConfigurationPanel hexConfigurationPanel; + + private byte[] bytes; + + public HexArea(ContentPanel contentPanel, JNode node) { + super(contentPanel, node); + binaryNode = node; + config = new HexAreaConfiguration(); + hexPreviewPanel = new HexPreviewPanel(config); + + initView(); + applyTheme(); + } + + @Override + public @NotNull ICodeInfo getCodeInfo() { + return ICodeInfo.EMPTY; + } + + @Override + public void load() { + byte[] bytes = binaryNode.getCodeInfo().getCodeStr().getBytes(StandardCharsets.UTF_8); + setBytes(bytes); + if (getBytes().length > 0) { + // We set the caret after the first byte to prevent it from being highlighted + setCaretPosition(2); + } else { + setCaretPosition(0); + } + setLoaded(); + } + + @Override + public void refresh() { + + } + + @Override + public void loadSettings() { + super.loadSettings(); + applyTheme(); + } + + private void applyTheme() { + Font font = getContentPanel().getTabbedPane().getMainWindow().getSettings().getSmaliFont(); + setFont(font); + + Theme theme = contentPanel.getTabbedPane().getMainWindow().getEditorTheme(); + if (hexPreviewPanel != null) { + hexPreviewPanel.applyTheme(theme, font); + } + } + + private void initView() { + addCaretListener(new HexCaretListener()); + setLayout(new BorderLayout()); + setBorder(new EmptyBorder(0, 0, 0, 0)); + hexPreviewPanel.setFont(getFont()); + add(hexPreviewPanel, BorderLayout.EAST); + } + + private void setBytes(byte[] bytes) { + this.bytes = bytes; + + String text; + if (bytes.length > 0) { + byte[] hexChars = new byte[bytes.length * 4 - 2]; + + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 4] = HEX_ARRAY[v >>> 4]; + hexChars[j * 4 + 1] = HEX_ARRAY[v & 0x0F]; + if (j != bytes.length - 1) { + hexChars[j * 4 + 2] = ' '; + hexChars[j * 4 + 3] = (byte) ((j % config.bytesPerLine == config.bytesPerLine - 1) ? '\n' : ' '); + } + } + text = new String(hexChars, StandardCharsets.UTF_8); + } else { + text = ""; + } + setText(text); + hexPreviewPanel.setBytes(bytes); + hexConfigurationPanel.setBytes(bytes); + } + + public byte[] getBytes() { + return bytes; + } + + public void setConfigurationPanel(HexConfigurationPanel hexConfigurationPanel) { + this.hexConfigurationPanel = hexConfigurationPanel; + } + + @Override + public void copyAsStyledText() { + String text = getSelectedText(); + if (text != null && !StringUtils.isEmpty(text)) { + text = text + .replace(" ", "") + .replace("\n", ""); + UiUtils.copyToClipboard(text); + } + } + + public HexAreaConfiguration getConfiguration() { + return config; + } + + private class HexCaretListener implements CaretListener { + private boolean isListening = true; + private int previousCaretDot = -1; + + @Override + public void caretUpdate(CaretEvent caretEvent) { + int dot = caretEvent.getDot(); + int mark = caretEvent.getMark(); + + if (!isListening) { + return; + } + + if (dot % 2 == 1) { + if (previousCaretDot > dot) { + if (mark == dot) { + mark--; + } + dot--; + } else { + if (mark == dot) { + mark++; + } + dot++; + } + + isListening = false; + HexArea.this.setCaretPosition(mark); + HexArea.this.moveCaretPosition(dot); + isListening = true; + } + + if (previousCaretDot != dot) { + onTextCursorMoved(dot, mark); + } + + previousCaretDot = dot; + } + + private void onTextCursorMoved(int dot, int mark) { + hexConfigurationPanel.setOffset(dot / 4); + + int startIndex = Math.min(dot, mark); + int endIndex = Math.max(dot, mark); + int startOffset = startIndex / 4; + int endOffset = endIndex / 4; + if (startIndex % 4 == 2 && endIndex == startIndex + 2) { + // Highlighted an empty space + hexPreviewPanel.clearHighlights(); + return; + } + if (startOffset < endOffset && startIndex % 4 == 2) { + startOffset++; + } + if (endOffset > startOffset && endIndex % 4 == 0) { + endOffset--; + } + hexPreviewPanel.highlightBytes(startOffset, endOffset); + } + } +} diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/HexAreaConfiguration.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/HexAreaConfiguration.java new file mode 100644 index 000000000..8ae033025 --- /dev/null +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/HexAreaConfiguration.java @@ -0,0 +1,7 @@ +package jadx.gui.ui.codearea; + +public class HexAreaConfiguration { + public int bytesPerLine = 16; + + public boolean littleEndian = false; +} diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/HexConfigurationPanel.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/HexConfigurationPanel.java new file mode 100644 index 000000000..b64b561c0 --- /dev/null +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/HexConfigurationPanel.java @@ -0,0 +1,139 @@ +package jadx.gui.ui.codearea; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ItemEvent; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; + +import org.apache.commons.lang3.ArrayUtils; + +public class HexConfigurationPanel extends JPanel { + private final List formatters = new ArrayList<>(); + + private final HexAreaConfiguration config; + + private byte[] bytes = null; + private Integer offset = null; + + private int row = 0; + + public HexConfigurationPanel(HexAreaConfiguration configuration) { + this.config = configuration; + + setLayout(new GridBagLayout()); + addValueFormat("Signed 8 bit", 1, b -> Integer.toString(b.get())); + addValueFormat("Unsigned 8 bit", 1, b -> Integer.toString(b.get() & 0xFF)); + addValueFormat("Signed 16 bit", 2, b -> Short.toString(b.getShort())); + addValueFormat("Unsigned 16 bit", 2, b -> Integer.toString(b.getShort() & 0xFFFF)); + addValueFormat("Float 32 bit", 4, b -> Float.toString(b.getFloat())); + addValueFormat("Signed 32 bit", 4, b -> Integer.toString(b.getInt())); + addValueFormat("Unsigned 32 bit", 4, b -> Integer.toUnsignedString(b.getInt())); + addValueFormat("Signed 64 bit", 8, b -> Long.toString(b.getLong())); + addValueFormat("Float 64 bit", 8, b -> Double.toString(b.getDouble())); + addValueFormat("Unsigned 64 bit", 8, b -> Long.toUnsignedString(b.getLong())); + addValueFormat("Hexadecimal", 1, b -> Integer.toString(b.get(), 16)); + addValueFormat("Octal", 1, b -> Integer.toString(b.get(), 8)); + addValueFormat("Binary", 1, b -> Integer.toString(b.get(), 2)); + + GridBagConstraints constraints; + constraints = getConstraints(); + constraints.gridwidth = 2; + JCheckBox littleEndianCheckBox = new JCheckBox("Little endian", false); + littleEndianCheckBox.addItemListener(ev -> { + config.littleEndian = ev.getStateChange() == ItemEvent.SELECTED; + reloadOffset(); + }); + add(littleEndianCheckBox, constraints); + + // Workaround to force widgets to start from the top (otherwise centered) + constraints = getConstraints(); + constraints.weighty = 1; + add(new JLabel(" "), constraints); + } + + public void setOffset(int offset) { + this.offset = offset; + reloadOffset(); + } + + public void setBytes(byte[] bytes) { + this.bytes = bytes; + } + + private void reloadOffset() { + if (bytes == null || offset == null) { + return; + } + + for (int i = 0; i < formatters.size(); i++) { + ValueFormatter formatter = formatters.get(i); + if (canDisplay(offset, formatter.dataSize)) { + ByteBuffer buffer = decodeByteArray(offset, formatter.dataSize); + String value = formatter.function.apply(buffer); + ((JTextField) getComponent(i * 2 + 1)).setText(value); + } + } + } + + private GridBagConstraints getConstraints() { + GridBagConstraints constraints = new GridBagConstraints(); + constraints.insets = new Insets(5, 5, 5, 5); + constraints.gridy = row; + row++; + return constraints; + } + + private void addValueFormat(String name, int dataSize, Function formatter) { + formatters.add(new ValueFormatter(dataSize, formatter)); + + GridBagConstraints constraints = getConstraints(); + constraints.gridx = 0; + constraints.anchor = GridBagConstraints.WEST; + add(new JLabel(name), constraints); + + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.gridx = 1; + + JTextField textField = new JTextField(); + textField.setEditable(false); + + add(textField, constraints); + } + + private boolean canDisplay(int offset, int size) { + return offset + size <= bytes.length; + } + + private ByteBuffer decodeByteArray(int offset, int size) { + byte[] chunk = sliceBytes(offset, size); + if (config.littleEndian) { + ArrayUtils.reverse(chunk); + } + return ByteBuffer.wrap(chunk); + } + + private byte[] sliceBytes(int offset, int size) { + byte[] slice = new byte[size]; + System.arraycopy(bytes, offset, slice, 0, size); + return slice; + } + + private static class ValueFormatter { + public final int dataSize; + public final Function function; + + public ValueFormatter(int dataSize, Function function) { + this.dataSize = dataSize; + this.function = function; + } + } +} diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/HexPreviewPanel.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/HexPreviewPanel.java new file mode 100644 index 000000000..20df6f179 --- /dev/null +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/HexPreviewPanel.java @@ -0,0 +1,94 @@ +package jadx.gui.ui.codearea; + +import java.awt.Color; +import java.awt.Font; + +import javax.swing.JTextArea; +import javax.swing.border.MatteBorder; +import javax.swing.text.BadLocationException; +import javax.swing.text.DefaultHighlighter; +import javax.swing.text.Highlighter; + +import org.fife.ui.rsyntaxtextarea.SyntaxScheme; +import org.fife.ui.rsyntaxtextarea.Theme; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HexPreviewPanel extends JTextArea { + private static final Logger LOG = LoggerFactory.getLogger(HexPreviewPanel.class); + + private final HexAreaConfiguration config; + + private byte[] bytes = new byte[0]; + + private Color highlightColor = Color.YELLOW; + private boolean hasHighlight = false; + + public HexPreviewPanel(HexAreaConfiguration configuration) { + super(0, configuration.bytesPerLine); + + this.config = configuration; + initView(); + } + + public void setBytes(byte[] bytes) { + this.bytes = bytes; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < bytes.length; i++) { + char c = (char) bytes[i]; + if (c <= 0x1f || (c & (1 << 7)) != 0) { + sb.append('.'); + } else { + sb.append(c); + } + if (i != bytes.length - 1 && i % config.bytesPerLine == config.bytesPerLine - 1) { + sb.append('\n'); + } + } + setText(sb.toString()); + } + + public void clearHighlights() { + hasHighlight = false; + getHighlighter().removeAllHighlights(); + } + + public void highlightBytes(int startOffset, int endOffset) { + if (hasHighlight) { + getHighlighter().removeAllHighlights(); + } + + // Include line breaks in the index + startOffset += startOffset / config.bytesPerLine; + endOffset += endOffset / config.bytesPerLine; + + Highlighter.HighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter(highlightColor); + try { + getHighlighter().addHighlight(startOffset, endOffset + 1, painter); + } catch (BadLocationException e) { + LOG.error("Unable to highlight bytes " + startOffset + ":" + endOffset, e); + } + hasHighlight = true; + } + + public void setHighlightColor(Color highlightColor) { + this.highlightColor = highlightColor; + } + + public void setBorderColor(Color borderColor) { + setBorder(new MatteBorder(0, 2, 0, 0, borderColor)); + } + + public void applyTheme(Theme theme, Font font) { + setBackground(theme.bgColor); + setHighlightColor(theme.selectionBG); + setBorderColor(theme.gutterBorderColor); + setDisabledTextColor(theme.scheme.getStyle(SyntaxScheme.IDENTIFIER).foreground); + setFont(font); + } + + private void initView() { + setEnabled(false); + setEditable(false); + } +} diff --git a/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties b/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties index fbe0218f9..8c226f49c 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties @@ -199,7 +199,7 @@ preferences.cfg=CFG-Grafiken für Methoden generieren (im 'dot'-Format) preferences.raw_cfg=RAW CFG-Grafiken generieren #preferences.integerFormat=Integer format preferences.font=Schrift ändern -preferences.smali_font=Schrifteditor +#preferences.smali_font= preferences.laf_theme=Thema preferences.theme=Thema ändern preferences.start_jobs=Autom. Hintergrunddekompilierung starten diff --git a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties index 37aeee703..67e2ded09 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties @@ -199,7 +199,7 @@ preferences.cfg=Generate methods CFG graphs (in 'dot' format) preferences.raw_cfg=Generate RAW CFG graphs preferences.integerFormat=Integer format preferences.font=Editor font -preferences.smali_font=Smali Editor font +preferences.smali_font=Monospaced font (Smali/Hex) preferences.laf_theme=Theme preferences.theme=Editor theme preferences.start_jobs=Auto start background decompilation diff --git a/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties b/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties index 270cf5766..66b0ccfbf 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties @@ -199,7 +199,7 @@ preferences.cfg=메소드 CFG 그래프 생성 ('dot' 포맷) preferences.raw_cfg=RAW CFG 그래프 생성 #preferences.integerFormat=Integer format preferences.font=에디터 글씨체 -preferences.smali_font=Smali 에디터 글씨체 +#preferences.smali_font= preferences.laf_theme=테마 preferences.theme=에디터 테마 preferences.start_jobs=백그라운드에서 디컴파일 자동 시작 diff --git a/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties b/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties index 185a12fdf..218b9e6b3 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties @@ -199,7 +199,7 @@ preferences.cfg=Gera gráficos de métodos CFG no formato de pontos ('dot') preferences.raw_cfg=Gera gráficos CFG no formato RAW #preferences.integerFormat=Integer format preferences.font=Fonte do editor -preferences.smali_font=Fonte do editor de smali +#preferences.smali_font= preferences.laf_theme=Tema preferences.theme=Tema do editor preferences.start_jobs=Inicializar descompilação automaticamente em segundo-plano diff --git a/jadx-gui/src/main/resources/i18n/Messages_ru_RU.properties b/jadx-gui/src/main/resources/i18n/Messages_ru_RU.properties index 534f5dc6f..f1c7d9475 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_ru_RU.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_ru_RU.properties @@ -199,7 +199,7 @@ preferences.cfg=Методы генерации графиков CFG (в "dot" preferences.raw_cfg=Генерировать необработанные графики CFG #preferences.integerFormat=Integer format preferences.font=Шрифт редактора Java -preferences.smali_font=Шрифт редактора smali +#preferences.smali_font= preferences.laf_theme=Тема приложения preferences.theme=Тема редактора preferences.start_jobs=Автоматическая декомпиляция diff --git a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties index bad4e3133..00d78451b 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties @@ -199,7 +199,7 @@ preferences.cfg=生成方法的 CFG 图('.dot') preferences.raw_cfg=生成原始的 CFG 图 preferences.integerFormat=数值格式化 preferences.font=编辑器字体 -preferences.smali_font=Smali编辑器字体 +#preferences.smali_font= preferences.laf_theme=主题 preferences.theme=编辑器主题 preferences.start_jobs=自动进行后台反编译 diff --git a/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties b/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties index ad1f305ae..5e88e1cb9 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties @@ -199,7 +199,7 @@ preferences.cfg=產生方法 CFG 圖表 ('dot' 格式) preferences.raw_cfg=產生 RAW CFG 圖表 preferences.integerFormat=整數模式 preferences.font=編輯器字型 -preferences.smali_font=Smali 編輯器字型 +#preferences.smali_font= preferences.laf_theme=主題 preferences.theme=編輯器主題 preferences.start_jobs=自動開始背景反編譯