Skip to main content

libcdio_rs/iso9660/
util.rs

1// Copyright (C) 2026 Shiva Kiran Koninty <shiva@skran.xyz>
2//
3// This file is part of libcdio-rs.
4//
5// libcdio-rs is free software: you can redistribute it and/or
6// modify it under the terms of the GNU General Public License as
7// published by the Free Software Foundation, either version 3 of the
8// License, or (at your option) any later version.
9//
10// libcdio-rs is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13// General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with libcdio-rs. If not, see <https://www.gnu.org/licenses/>.
17
18//! Utility and data structure conversion routines.
19
20use std::{error::Error, ffi::c_void};
21
22use libcdio_sys::_CdioList;
23use time::{Date, OffsetDateTime, Time, UtcOffset};
24
25/// Convert `tm` representing local time to a `OffsetDateTime`.
26pub(crate) fn convert_tm_local(
27    tm: libcdio_sys::tm,
28) -> Result<OffsetDateTime, Box<dyn Error + Send + Sync>> {
29    const TM_YEAR_OFFSET: i32 = 1900;
30    const TM_ORDINAL_DAY_OFFSET: u16 = 1;
31    let date = Date::from_ordinal_date(
32        tm.tm_year + TM_YEAR_OFFSET,
33        u16::try_from(tm.tm_yday)? + TM_ORDINAL_DAY_OFFSET,
34    )?;
35    let time = Time::from_hms(
36        u8::try_from(tm.tm_hour)?,
37        u8::try_from(tm.tm_min)?,
38        u8::try_from(tm.tm_sec)?,
39    )?;
40
41    Ok(OffsetDateTime::new_in_offset(
42        date,
43        time,
44        UtcOffset::local_offset_at(OffsetDateTime::new_utc(date, time))?,
45    ))
46}
47
48/// Returns a vec of pointers to the data of the cdio list.
49/// Frees the list nodes, without freeing the data.
50/// # Safety
51/// - `cdio_list` must not be null.
52/// - The list data must be owned by the caller.
53pub unsafe fn cdiolist_to_vec(cdio_list: *mut _CdioList) -> Vec<*mut c_void> {
54    let mut list = Vec::new();
55    let mut cur = unsafe { libcdio_sys::_cdio_list_begin(cdio_list) };
56    while !cur.is_null() {
57        let data = unsafe { libcdio_sys::_cdio_list_node_data(cur) };
58        list.push(data);
59        cur = unsafe { libcdio_sys::_cdio_list_node_next(cur) };
60    }
61
62    unsafe {
63        libcdio_sys::_cdio_list_free(cdio_list, 0, None);
64    }
65
66    list
67}
68
69#[cfg(test)]
70mod tests {
71    use std::ffi::CString;
72
73    #[test]
74    fn cdiolist_to_vec() {
75        let a = CString::new("This is A").unwrap();
76        let b = CString::new("This is B").unwrap();
77
78        let cdiolist = unsafe { libcdio_sys::_cdio_list_new() };
79        unsafe { libcdio_sys::_cdio_list_append(cdiolist, a.into_raw().cast()) };
80        unsafe { libcdio_sys::_cdio_list_append(cdiolist, b.into_raw().cast()) };
81
82        let list = unsafe { super::cdiolist_to_vec(cdiolist) };
83        let a = unsafe { CString::from_raw(list[0].cast()) };
84        let b = unsafe { CString::from_raw(list[1].cast()) };
85
86        assert_eq!(&a, c"This is A");
87        assert_eq!(&b, c"This is B");
88    }
89}