diff --git a/Cargo.lock b/Cargo.lock index a24f72b..a182304 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -363,6 +363,7 @@ dependencies = [ "cwextab", "dyn-clone", "enable-ansi-support", + "encoding_rs", "filetime", "fixedbitset 0.5.7", "flagset", diff --git a/Cargo.toml b/Cargo.toml index 848e1d7..3906823 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ strip = "debuginfo" codegen-units = 1 [dependencies] +encoding_rs = "0.8" aes = "0.8" anyhow = { version = "1.0", features = ["backtrace"] } ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "write_symbol_table" } diff --git a/src/obj/symbols.rs b/src/obj/symbols.rs index 46b2a4e..56659b3 100644 --- a/src/obj/symbols.rs +++ b/src/obj/symbols.rs @@ -175,8 +175,10 @@ pub enum ObjDataKind { Float, Double, String, + ShiftJIS, String16, StringTable, + ShiftJISTable, String16Table, Int, Short, diff --git a/src/util/asm.rs b/src/util/asm.rs index d54951b..3fe73c5 100644 --- a/src/util/asm.rs +++ b/src/util/asm.rs @@ -668,6 +668,38 @@ where W: Write + ?Sized { Ok(()) } +use encoding_rs::SHIFT_JIS; + +fn write_string_shiftjis(w: &mut W, data: &[u8]) -> Result<()> +where W: Write + ?Sized { + if data.last() != Some(&0x00) { + bail!("Non-terminated Shift-JIS string"); + } + + let raw_data = &data[..data.len() - 1]; + + // Decode then write SJIS as comment above byte array + let (cow, _, _) = SHIFT_JIS.decode(raw_data); + write!(w, "\t# ")?; + for c in cow.chars() { + match c { + '#' => write!(w, "\\#")?, + _ => write!(w, "{}", c)?, + } + } + + write!(w, "\n\t.byte ")?; + for (i, &b) in data.iter().enumerate() { + write!(w, "0x{:02X}", b)?; + if i + 1 != data.len() { + write!(w, ", ")?; + } + } + + writeln!(w)?; + Ok(()) +} + fn write_string16(w: &mut W, data: &[u16]) -> Result<()> where W: Write + ?Sized { if matches!(data.last(), Some(&b) if b == 0) { @@ -705,6 +737,12 @@ where W: Write + ?Sized { ObjDataKind::String => { return write_string(w, data); } + ObjDataKind::ShiftJIS => { + if data.is_empty() || data.last() != Some(&0x00) { + anyhow::bail!("Non-terminated Shift-JIS string"); + } + return write_string_shiftjis(w, data); + } ObjDataKind::String16 => { if data.len() % 2 != 0 { bail!("Attempted to write wstring with length {:#X}", data.len()); @@ -734,6 +772,12 @@ where W: Write + ?Sized { } return Ok(()); } + ObjDataKind::ShiftJISTable => { + for slice in data.split_inclusive(|&b| b == 0) { + write_string_shiftjis(w, slice)?; + } + return Ok(()); + } _ => {} } let chunk_size = match data_kind { @@ -742,7 +786,9 @@ where W: Write + ?Sized { ObjDataKind::Byte | ObjDataKind::Byte8 | ObjDataKind::Double => 8, ObjDataKind::String | ObjDataKind::String16 + | ObjDataKind::ShiftJIS | ObjDataKind::StringTable + | ObjDataKind::ShiftJISTable | ObjDataKind::String16Table => unreachable!(), }; for chunk in remain.chunks(chunk_size) { diff --git a/src/util/config.rs b/src/util/config.rs index 2ee8d1a..743a8ee 100644 --- a/src/util/config.rs +++ b/src/util/config.rs @@ -329,8 +329,10 @@ fn symbol_data_kind_to_str(kind: ObjDataKind) -> Option<&'static str> { ObjDataKind::Float => Some("float"), ObjDataKind::Double => Some("double"), ObjDataKind::String => Some("string"), + ObjDataKind::ShiftJIS => Some("sjis"), ObjDataKind::String16 => Some("wstring"), ObjDataKind::StringTable => Some("string_table"), + ObjDataKind::ShiftJISTable => Some("sjis_table"), ObjDataKind::String16Table => Some("wstring_table"), ObjDataKind::Int => Some("int"), ObjDataKind::Short => Some("short"), @@ -382,8 +384,10 @@ fn symbol_data_kind_from_str(s: &str) -> Option { "float" => Some(ObjDataKind::Float), "double" => Some(ObjDataKind::Double), "string" => Some(ObjDataKind::String), + "sjis" => Some(ObjDataKind::ShiftJIS), "wstring" => Some(ObjDataKind::String16), "string_table" => Some(ObjDataKind::StringTable), + "sjis_table" => Some(ObjDataKind::ShiftJISTable), "wstring_table" => Some(ObjDataKind::String16Table), "int" => Some(ObjDataKind::Int), "short" => Some(ObjDataKind::Short),