pub mod error;
pub mod raster;
pub mod types;
pub mod vector;
pub use error::{oxigdal_get_last_error, oxigdal_string_free};
pub use raster::*;
pub use types::*;
pub use vector::*;
#[unsafe(no_mangle)]
pub extern "C" fn oxigdal_init() -> OxiGdalErrorCode {
#[cfg(feature = "std")]
{
use std::sync::Once;
static INIT: Once = Once::new();
INIT.call_once(|| {
});
}
OxiGdalErrorCode::Success
}
#[unsafe(no_mangle)]
pub extern "C" fn oxigdal_cleanup() -> OxiGdalErrorCode {
error::clear_last_error();
OxiGdalErrorCode::Success
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn oxigdal_is_format_supported(
path: *const std::os::raw::c_char,
) -> std::os::raw::c_int {
if path.is_null() {
return 0;
}
let path_str = unsafe {
match std::ffi::CStr::from_ptr(path).to_str() {
Ok(s) => s,
Err(_) => return 0,
}
};
let ext = std::path::Path::new(path_str)
.extension()
.and_then(|e| e.to_str())
.unwrap_or("");
match ext.to_lowercase().as_str() {
"tif" | "tiff" | "geotiff" => 1,
"json" | "geojson" => 1,
"shp" | "shapefile" => 1,
"gpkg" | "geopackage" => 1,
"png" | "jpg" | "jpeg" => 1,
_ => 0,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn oxigdal_buffer_alloc(
width: std::os::raw::c_int,
height: std::os::raw::c_int,
channels: std::os::raw::c_int,
) -> *mut OxiGdalBuffer {
if width <= 0 || height <= 0 || channels <= 0 {
error::set_last_error("Invalid buffer dimensions".to_string());
return std::ptr::null_mut();
}
let length = (width * height * channels) as usize;
let layout = std::alloc::Layout::from_size_align(length, 1);
let data = match layout {
Ok(layout) => unsafe { std::alloc::alloc(layout) },
Err(_) => {
error::set_last_error("Failed to create buffer layout".to_string());
return std::ptr::null_mut();
}
};
if data.is_null() {
error::set_last_error("Failed to allocate buffer memory".to_string());
return std::ptr::null_mut();
}
unsafe {
std::ptr::write_bytes(data, 0, length);
}
let buffer = Box::new(OxiGdalBuffer {
data,
length,
width,
height,
channels,
});
Box::into_raw(buffer)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn oxigdal_buffer_free(buffer: *mut OxiGdalBuffer) {
if buffer.is_null() {
return;
}
unsafe {
let buf = Box::from_raw(buffer);
if !buf.data.is_null() {
let layout = std::alloc::Layout::from_size_align_unchecked(buf.length, 1);
std::alloc::dealloc(buf.data, layout);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_init_cleanup() {
let result = oxigdal_init();
assert_eq!(result, OxiGdalErrorCode::Success);
let result = oxigdal_cleanup();
assert_eq!(result, OxiGdalErrorCode::Success);
}
#[test]
fn test_format_support() {
unsafe {
let path_tiff = std::ffi::CString::new("/path/to/file.tif").expect("valid string");
let supported = oxigdal_is_format_supported(path_tiff.as_ptr());
assert_eq!(supported, 1);
let path_json = std::ffi::CString::new("/path/to/file.geojson").expect("valid string");
let supported = oxigdal_is_format_supported(path_json.as_ptr());
assert_eq!(supported, 1);
let path_unknown = std::ffi::CString::new("/path/to/file.xyz").expect("valid string");
let supported = oxigdal_is_format_supported(path_unknown.as_ptr());
assert_eq!(supported, 0);
}
}
#[test]
fn test_buffer_alloc_free() {
unsafe {
let buffer = oxigdal_buffer_alloc(256, 256, 3);
assert!(!buffer.is_null());
let buf = &*buffer;
assert_eq!(buf.width, 256);
assert_eq!(buf.height, 256);
assert_eq!(buf.channels, 3);
assert_eq!(buf.length, 256 * 256 * 3);
assert!(!buf.data.is_null());
oxigdal_buffer_free(buffer);
}
}
#[test]
fn test_buffer_alloc_invalid() {
unsafe {
let buffer = oxigdal_buffer_alloc(-1, 256, 3);
assert!(buffer.is_null());
let buffer = oxigdal_buffer_alloc(256, -1, 3);
assert!(buffer.is_null());
let buffer = oxigdal_buffer_alloc(256, 256, 0);
assert!(buffer.is_null());
}
}
}