use std::ffi::{CStr, CString};
use std::io::Cursor;
use std::os::raw::c_char;
use std::path::Path;
use std::ptr;
use std::slice;
use crate::core::dep;
use crate::core::identify::{identify, identify_reader};
use crate::core::metadata;
use crate::error::Result;
#[cfg(feature = "classfile")]
use crate::core::classfile;
#[cfg(feature = "classfile")]
use std::path::PathBuf;
fn to_c_string(result: Result<String>) -> *mut c_char {
match result {
Ok(s) => match CString::new(s) {
Ok(cs) => cs.into_raw(),
Err(e) => {
eprintln!("modcrawl: CString error: {e}");
ptr::null_mut()
}
},
Err(e) => {
eprintln!("modcrawl: {e:?}");
ptr::null_mut()
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn modcrawl_identify(path: *const c_char) -> *mut c_char {
if path.is_null() {
return ptr::null_mut();
}
let Ok(path_str) = unsafe { CStr::from_ptr(path) }.to_str() else {
return ptr::null_mut();
};
to_c_string(identify(Path::new(path_str)).map(|m| m.to_string()))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn modcrawl_identify_bytes(data: *const u8, len: usize) -> *mut c_char {
if data.is_null() || len == 0 {
return ptr::null_mut();
}
let slice = unsafe { slice::from_raw_parts(data, len) };
let mut cursor = Cursor::new(slice);
to_c_string(identify_reader(&mut cursor).map(|m| m.to_string()))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn modcrawl_metadata(path: *const c_char) -> *mut c_char {
if path.is_null() {
return ptr::null_mut();
}
let Ok(path_str) = unsafe { CStr::from_ptr(path) }.to_str() else {
return ptr::null_mut();
};
to_c_string(metadata::read_metadata(Path::new(path_str)).map(|m| m.to_string()))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn modcrawl_metadata_json(path: *const c_char) -> *mut c_char {
if path.is_null() {
return ptr::null_mut();
}
let Ok(path_str) = unsafe { CStr::from_ptr(path) }.to_str() else {
return ptr::null_mut();
};
to_c_string(
metadata::read_metadata(Path::new(path_str))
.and_then(|m| serde_json::to_string(&m).map_err(Into::into)),
)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn modcrawl_metadata_bytes(data: *const u8, len: usize) -> *mut c_char {
if data.is_null() || len == 0 {
return ptr::null_mut();
}
let slice = unsafe { slice::from_raw_parts(data, len) };
let mut cursor = Cursor::new(slice);
to_c_string(metadata::read_metadata_reader(&mut cursor).map(|m| m.to_string()))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn modcrawl_metadata_json_bytes(data: *const u8, len: usize) -> *mut c_char {
if data.is_null() || len == 0 {
return ptr::null_mut();
}
let slice = unsafe { slice::from_raw_parts(data, len) };
let mut cursor = Cursor::new(slice);
to_c_string(
metadata::read_metadata_reader(&mut cursor)
.and_then(|m| serde_json::to_string(&m).map_err(Into::into)),
)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn modcrawl_deps(path: *const c_char, include_jij: bool) -> *mut c_char {
if path.is_null() {
return ptr::null_mut();
}
let Ok(path_str) = unsafe { CStr::from_ptr(path) }.to_str() else {
return ptr::null_mut();
};
to_c_string(dep::analyze(Path::new(path_str), include_jij).map(|r| r.to_string()))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn modcrawl_deps_json(path: *const c_char, include_jij: bool) -> *mut c_char {
if path.is_null() {
return ptr::null_mut();
}
let Ok(path_str) = unsafe { CStr::from_ptr(path) }.to_str() else {
return ptr::null_mut();
};
to_c_string(
dep::analyze(Path::new(path_str), include_jij)
.and_then(|r| serde_json::to_string(&r).map_err(Into::into)),
)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn modcrawl_deps_bytes(
data: *const u8,
len: usize,
include_jij: bool,
) -> *mut c_char {
if data.is_null() || len == 0 {
return ptr::null_mut();
}
let slice = unsafe { slice::from_raw_parts(data, len) };
let mut cursor = Cursor::new(slice);
to_c_string(dep::analyze_reader(&mut cursor, include_jij).map(|r| r.to_string()))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn modcrawl_deps_json_bytes(
data: *const u8,
len: usize,
include_jij: bool,
) -> *mut c_char {
if data.is_null() || len == 0 {
return ptr::null_mut();
}
let slice = unsafe { slice::from_raw_parts(data, len) };
let mut cursor = Cursor::new(slice);
to_c_string(
dep::analyze_reader(&mut cursor, include_jij)
.and_then(|r| serde_json::to_string(&r).map_err(Into::into)),
)
}
#[cfg(feature = "classfile")]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn modcrawl_classes_json(path: *const c_char) -> *mut c_char {
if path.is_null() {
return ptr::null_mut();
}
let Ok(path_str) = unsafe { CStr::from_ptr(path) }.to_str() else {
return ptr::null_mut();
};
to_c_string(
classfile::list_classes(Path::new(path_str))
.and_then(|entries| serde_json::to_string(&entries).map_err(Into::into)),
)
}
#[cfg(feature = "classfile")]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn modcrawl_grep_json(
path: *const c_char,
pattern: *const c_char,
) -> *mut c_char {
if path.is_null() || pattern.is_null() {
return ptr::null_mut();
}
let Ok(path_str) = unsafe { CStr::from_ptr(path) }.to_str() else {
return ptr::null_mut();
};
let Ok(pattern_str) = unsafe { CStr::from_ptr(pattern) }.to_str() else {
return ptr::null_mut();
};
to_c_string(
classfile::grep(Path::new(path_str), pattern_str)
.and_then(|matches| serde_json::to_string(&matches).map_err(Into::into)),
)
}
#[cfg(feature = "classfile")]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn modcrawl_mixins_json(path: *const c_char) -> *mut c_char {
if path.is_null() {
return ptr::null_mut();
}
let Ok(path_str) = unsafe { CStr::from_ptr(path) }.to_str() else {
return ptr::null_mut();
};
to_c_string(
classfile::mixins(Path::new(path_str))
.and_then(|entries| serde_json::to_string(&entries).map_err(Into::into)),
)
}
#[cfg(feature = "classfile")]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn modcrawl_dupes_json(paths: *mut *const c_char) -> *mut c_char {
if paths.is_null() {
return ptr::null_mut();
}
let mut path_vec: Vec<PathBuf> = Vec::new();
let mut i = 0;
loop {
let p = unsafe { *paths.add(i) };
if p.is_null() {
break;
}
if let Ok(s) = unsafe { CStr::from_ptr(p) }.to_str() {
path_vec.push(PathBuf::from(s));
}
i += 1;
}
let path_refs: Vec<&Path> = path_vec.iter().map(PathBuf::as_path).collect();
to_c_string(
classfile::find_duplicates(&path_refs)
.and_then(|entries| serde_json::to_string(&entries).map_err(Into::into)),
)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn modcrawl_free_string(s: *mut c_char) {
if s.is_null() {
return;
}
unsafe {
let _ = CString::from_raw(s);
}
}