Skip to content

Commit

Permalink
fix: unicode filenames on Linux
Browse files Browse the repository at this point in the history
This bug caused CJK chars in filename to be stripped out on Linux.
For example, `/media/mydisk/fooにほん.rar`  would result in
`/media/mydisk/foo` so the open will fail

due to

```cpp
    if (r->ArcNameW!=nullptr && *r->ArcNameW!=0)
      ArcName=r->ArcNameW;
    else
      CharToWide(AnsiArcName,ArcName);

    Data->Arc.Open(ArcName,FMF_OPENSHARED)
```

in `Data->Arc.Open`, ArcName is converted with `WideToChar` causing the CJK bytes to get lost.
So we pass in as AnsiArcName, so `CharToWide` is called first.

Co-authored-by: Danyel <[email protected]>
Fixes #44
  • Loading branch information
ttys3 authored and muja committed Aug 31, 2024
1 parent 254025c commit a331d22
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 4 deletions.
Binary file added data/unicodefilename❤️.rar
Binary file not shown.
5 changes: 5 additions & 0 deletions src/open_archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use super::*;
use std::ffi::CString;
use std::fmt;
use std::os::raw::{c_int, c_uint};
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf};
use std::ptr::NonNull;
use widestring::WideCString;
Expand Down Expand Up @@ -233,10 +234,14 @@ impl<Mode: OpenMode> OpenArchive<Mode, CursorBeforeHeader> {
password: Option<&[u8]>,
recover: Option<&mut Option<Self>>,
) -> UnrarResult<Self> {
#[cfg(not(target_os = "linux"))]
let filename = WideCString::from_os_str(&filename).unwrap();
#[cfg(target_os = "linux")]
let filename = CString::new(filename.as_os_str().as_bytes()).unwrap();

let mut data =
native::OpenArchiveDataEx::new(filename.as_ptr() as *const _, Mode::VALUE as u32);

let handle =
NonNull::new(unsafe { native::RAROpenArchiveEx(&mut data as *mut _) } as *mut _);

Expand Down
6 changes: 6 additions & 0 deletions tests/utf8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@ fn unicode_list() {
let mut entries = Archive::new("data/unicode.rar").open_for_listing().unwrap();
assert_eq!(entries.next().unwrap().unwrap().filename, PathBuf::from("te…―st✌"));
}

#[test]
fn unicode_file() {
let mut entries = Archive::new("data/unicodefilename❤️.rar").open_for_listing().unwrap();
assert_eq!(entries.next().unwrap().unwrap().filename, PathBuf::from(".gitignore"));
}
4 changes: 2 additions & 2 deletions unrar_sys/examples/lister.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ fn main() {
&mut next_path as *mut String as LPARAM,
)
};
let mut header = HeaderData::default();
let mut header = HeaderDataEx::default();
let mut result = 0;
let mut process_result;
let mut first = true;
while result == 0 {
result = unsafe { RARReadHeader(handle, &mut header as *mut _) };
result = unsafe { RARReadHeaderEx(handle, &mut header as *mut _) };
if result != ERAR_SUCCESS {
if result != ERAR_END_ARCHIVE {
writeln!(&mut stderr, "Error opening: {}", result).unwrap();
Expand Down
8 changes: 6 additions & 2 deletions unrar_sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,9 +335,13 @@ impl OpenArchiveData {

impl OpenArchiveDataEx {
pub fn new(archive: *const wchar_t, mode: c_uint) -> Self {
#[cfg(not(target_os = "linux"))]
let (archive_name_w, archive_name) = (archive, std::ptr::null());
#[cfg(target_os = "linux")]
let (archive_name_w, archive_name) = (std::ptr::null(), archive as *const c_char);
OpenArchiveDataEx {
archive_name: std::ptr::null(),
archive_name_w: archive,
archive_name_w,
archive_name,
open_mode: mode,
open_result: 0,
comment_buffer: std::ptr::null_mut(),
Expand Down

0 comments on commit a331d22

Please sign in to comment.