Allow copying Shift JIS encoded string literals (#189)

* Update openssl and tokio for Cargo deny

* Allow copying Shift JIS encoded strings

* Override data type label for Shift JIS strings
This commit is contained in:
LagoLunatic 2025-04-17 12:07:05 -04:00 committed by GitHub
parent fbf85632ab
commit b40fae5140
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 53 additions and 26 deletions

1
Cargo.lock generated
View File

@ -3337,6 +3337,7 @@ dependencies = [
"cpp_demangle", "cpp_demangle",
"cwdemangle", "cwdemangle",
"cwextab", "cwextab",
"encoding_rs",
"filetime", "filetime",
"flagset", "flagset",
"gimli", "gimli",

View File

@ -167,6 +167,7 @@ notify-debouncer-full = { version = "0.5.0", optional = true }
shell-escape = { version = "0.1", optional = true } shell-escape = { version = "0.1", optional = true }
tempfile = { version = "3.19", optional = true } tempfile = { version = "3.19", optional = true }
time = { version = "0.3", optional = true } time = { version = "0.3", optional = true }
encoding_rs = "0.8.35"
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", optional = true } winapi = { version = "0.3", optional = true }

View File

@ -2,6 +2,7 @@ use alloc::{borrow::Cow, boxed::Box, format, string::String, vec::Vec};
use core::{ffi::CStr, fmt, fmt::Debug}; use core::{ffi::CStr, fmt, fmt::Debug};
use anyhow::{Result, bail}; use anyhow::{Result, bail};
use encoding_rs::SHIFT_JIS;
use object::Endian as _; use object::Endian as _;
use crate::{ use crate::{
@ -57,13 +58,18 @@ impl fmt::Display for DataType {
impl DataType { impl DataType {
pub fn display_labels(&self, endian: object::Endianness, bytes: &[u8]) -> Vec<String> { pub fn display_labels(&self, endian: object::Endianness, bytes: &[u8]) -> Vec<String> {
let mut strs = Vec::new(); let mut strs = Vec::new();
for literal in self.display_literals(endian, bytes) { for (literal, label_override) in self.display_literals(endian, bytes) {
strs.push(format!("{}: {}", self, literal)) let label = label_override.unwrap_or_else(|| format!("{}", self));
strs.push(format!("{}: {}", label, literal))
} }
strs strs
} }
pub fn display_literals(&self, endian: object::Endianness, bytes: &[u8]) -> Vec<String> { pub fn display_literals(
&self,
endian: object::Endianness,
bytes: &[u8],
) -> Vec<(String, Option<String>)> {
let mut strs = Vec::new(); let mut strs = Vec::new();
if self.required_len().is_some_and(|l| bytes.len() < l) { if self.required_len().is_some_and(|l| bytes.len() < l) {
log::warn!( log::warn!(
@ -87,56 +93,72 @@ impl DataType {
match self { match self {
DataType::Int8 => { DataType::Int8 => {
let i = i8::from_ne_bytes(bytes.try_into().unwrap()); let i = i8::from_ne_bytes(bytes.try_into().unwrap());
strs.push(format!("{:#x}", i)); strs.push((format!("{:#x}", i), None));
if i < 0 { if i < 0 {
strs.push(format!("{:#x}", ReallySigned(i))); strs.push((format!("{:#x}", ReallySigned(i)), None));
} }
} }
DataType::Int16 => { DataType::Int16 => {
let i = endian.read_i16_bytes(bytes.try_into().unwrap()); let i = endian.read_i16_bytes(bytes.try_into().unwrap());
strs.push(format!("{:#x}", i)); strs.push((format!("{:#x}", i), None));
if i < 0 { if i < 0 {
strs.push(format!("{:#x}", ReallySigned(i))); strs.push((format!("{:#x}", ReallySigned(i)), None));
} }
} }
DataType::Int32 => { DataType::Int32 => {
let i = endian.read_i32_bytes(bytes.try_into().unwrap()); let i = endian.read_i32_bytes(bytes.try_into().unwrap());
strs.push(format!("{:#x}", i)); strs.push((format!("{:#x}", i), None));
if i < 0 { if i < 0 {
strs.push(format!("{:#x}", ReallySigned(i))); strs.push((format!("{:#x}", ReallySigned(i)), None));
} }
} }
DataType::Int64 => { DataType::Int64 => {
let i = endian.read_i64_bytes(bytes.try_into().unwrap()); let i = endian.read_i64_bytes(bytes.try_into().unwrap());
strs.push(format!("{:#x}", i)); strs.push((format!("{:#x}", i), None));
if i < 0 { if i < 0 {
strs.push(format!("{:#x}", ReallySigned(i))); strs.push((format!("{:#x}", ReallySigned(i)), None));
} }
} }
DataType::Float => { DataType::Float => {
let bytes: [u8; 4] = bytes.try_into().unwrap(); let bytes: [u8; 4] = bytes.try_into().unwrap();
strs.push(format!("{:?}f", match endian { strs.push((
object::Endianness::Little => f32::from_le_bytes(bytes), format!("{:?}f", match endian {
object::Endianness::Big => f32::from_be_bytes(bytes), object::Endianness::Little => f32::from_le_bytes(bytes),
})); object::Endianness::Big => f32::from_be_bytes(bytes),
}),
None,
));
} }
DataType::Double => { DataType::Double => {
let bytes: [u8; 8] = bytes.try_into().unwrap(); let bytes: [u8; 8] = bytes.try_into().unwrap();
strs.push(format!("{:?}", match endian { strs.push((
object::Endianness::Little => f64::from_le_bytes(bytes), format!("{:?}", match endian {
object::Endianness::Big => f64::from_be_bytes(bytes), object::Endianness::Little => f64::from_le_bytes(bytes),
})); object::Endianness::Big => f64::from_be_bytes(bytes),
}),
None,
));
} }
DataType::Bytes => { DataType::Bytes => {
strs.push(format!("{:#?}", bytes)); strs.push((format!("{:#?}", bytes), None));
} }
DataType::String => { DataType::String => {
if let Ok(cstr) = CStr::from_bytes_until_nul(bytes) { if let Ok(cstr) = CStr::from_bytes_until_nul(bytes) {
strs.push(format!("{:?}", cstr)); strs.push((format!("{:?}", cstr), None));
}
if let Some(nul_idx) = bytes.iter().position(|&c| c == b'\0') {
let (cow, _, had_errors) = SHIFT_JIS.decode(&bytes[..nul_idx]);
if !had_errors {
let str = format!("{:?}", cow);
// Only add the Shift JIS string if it's different from the ASCII string.
if !strs.iter().any(|x| x.0 == str) {
strs.push((str, Some("Shift JIS".into())));
}
}
} }
} }
} }

View File

@ -444,8 +444,8 @@ pub fn relocation_context(
let literals = display_ins_data_literals(obj, ins); let literals = display_ins_data_literals(obj, ins);
if !literals.is_empty() { if !literals.is_empty() {
out.push(ContextItem::Separator); out.push(ContextItem::Separator);
for literal in literals { for (literal, label_override) in literals {
out.push(ContextItem::Copy { value: literal, label: None }); out.push(ContextItem::Copy { value: literal, label: label_override });
} }
} }
} }
@ -569,9 +569,9 @@ pub fn instruction_hover(
let literals = display_ins_data_literals(obj, resolved); let literals = display_ins_data_literals(obj, resolved);
if !literals.is_empty() { if !literals.is_empty() {
out.push(HoverItem::Separator); out.push(HoverItem::Separator);
for literal in literals { for (literal, label_override) in literals {
out.push(HoverItem::Text { out.push(HoverItem::Text {
label: format!("{}", ty), label: label_override.unwrap_or_else(|| format!("{}", ty)),
value: literal, value: literal,
color: HoverItemColor::Normal, color: HoverItemColor::Normal,
}); });
@ -764,7 +764,10 @@ pub fn display_ins_data_labels(obj: &Object, resolved: ResolvedInstructionRef) -
.unwrap_or_default() .unwrap_or_default()
} }
pub fn display_ins_data_literals(obj: &Object, resolved: ResolvedInstructionRef) -> Vec<String> { pub fn display_ins_data_literals(
obj: &Object,
resolved: ResolvedInstructionRef,
) -> Vec<(String, Option<String>)> {
let Some(reloc) = resolved.relocation else { let Some(reloc) = resolved.relocation else {
return Vec::new(); return Vec::new();
}; };