1use core_invoice::Profile;
4use core_invoice_formats::validate_xml;
5use std::ffi::{CStr, CString};
6use std::os::raw::{c_char, c_int};
7
8#[unsafe(no_mangle)]
10pub extern "C" fn core_invoice_validate_ubl(
11 xml: *const c_char,
12 profile: *const c_char,
13 err: *mut c_char,
14 err_len: usize,
15) -> c_int {
16 if xml.is_null() {
17 return write_err(err, err_len, "xml is null", 2);
18 }
19 let xml = unsafe { CStr::from_ptr(xml) }.to_string_lossy();
20 let profile = if profile.is_null() {
21 Profile::Pint
22 } else {
23 let s = unsafe { CStr::from_ptr(profile) }.to_string_lossy();
24 Profile::parse(s.as_ref()).unwrap_or(Profile::Pint)
25 };
26 match validate_xml(xml.as_ref(), Some(profile)) {
27 Ok(report) if report.ok() => 0,
28 Ok(report) => write_err(err, err_len, &report.to_string(), 1),
29 Err(e) => write_err(err, err_len, &e.to_string(), 2),
30 }
31}
32
33fn write_err(err: *mut c_char, err_len: usize, msg: &str, code: c_int) -> c_int {
34 if !err.is_null() && err_len > 0 {
35 let c = CString::new(msg.chars().take(err_len.saturating_sub(1)).collect::<String>())
36 .unwrap_or_else(|_| CString::new("error").unwrap());
37 let bytes = c.as_bytes_with_nul();
38 let n = bytes.len().min(err_len);
39 unsafe {
40 std::ptr::copy_nonoverlapping(bytes.as_ptr().cast::<c_char>(), err, n);
41 *err.add(n.saturating_sub(1)) = 0;
42 }
43 }
44 code
45}