exempi_sys/
lib.rs

1//
2// Copyright (c) 2016-2025, Hubert Figuière
3//
4// License: BSD-2-Clause
5// See top-level LICENSE file.
6//
7
8use libc::{c_char, c_int, size_t};
9
10pub mod consts;
11
12pub use consts::*;
13
14pub enum Xmp {}
15pub enum XmpFile {}
16pub enum XmpString {}
17pub enum XmpIterator {}
18
19#[derive(Clone, Copy, Eq, PartialEq, Debug)]
20#[repr(i32)]
21/// XMP errors.
22pub enum XmpError {
23    /* More or less generic error codes. */
24    /// Generic unknown error.
25    Unknown = 0,
26    /// Generic undefined error.
27    TBD = -1,
28    /// Generic unavailable error.
29    Unavailable = -2,
30    /// Generic bad object error.
31    BadObject = -3,
32    /// Generic bad parameter error.
33    BadParam = -4,
34    /// Generic bad value error.
35    BadValue = -5,
36    /// Generic assertion failure.
37    AssertFailure = -6,
38    /// Generic enforcement failure.
39    EnforceFailure = -7,
40    /// Generic unimplemented error.
41    Unimplemented = -8,
42    /// Generic internal failure.
43    InternalFailure = -9,
44    /// Generic deprecated error.
45    Deprecated = -10,
46    /// Generic external failure.
47    ExternalFailure = -11,
48    /// Generic user abort error.
49    UserAbort = -12,
50    /// Generic standard exception.
51    StdException = -13,
52    /// Generic unknown exception.
53    UnknownException = -14,
54    /// Generic out-of-memory error.
55    NoMemory = -15,
56
57    /* More specific parameter error codes.  */
58    /// Bad schema parameter.
59    BadSchema = -101,
60    /// Bad XPath parameter.
61    BadXPath = -102,
62    /// Bad options parameter.
63    BadOptions = -103,
64    /// Bad index parameter.
65    BadIndex = -104,
66    /// Bad iteration position.
67    BadIterPosition = -105,
68    /// XML parsing error.
69    BadParse = -106,
70    /// Serialization error.
71    BadSerialize = -107,
72    /// File format error.
73    BadFileFormat = -108,
74    /// No file handler found for format.
75    NoFileHandler = -109,
76    /// Data too large for JPEG file format.
77    TooLargeForJPEG = -110,
78
79    /* File format and internal structure error codes. */
80    /// XML format error.
81    BadXML = -201,
82    /// RDF format error.
83    BadRDF = -202,
84    /// XMP format error.
85    BadXMP = -203,
86    /// Empty iterator.
87    EmptyIterator = -204,
88    /// Unicode error.
89    BadUnicode = -205,
90    /// TIFF format error.
91    BadTIFF = -206,
92    /// JPEG format error.
93    BadJPEG = -207,
94    /// PSD format error.
95    BadPSD = -208,
96    /// PSIR format error.
97    BadPSIR = -209,
98    /// IPTC format error.
99    BadIPTC = -210,
100    /// MPEG format error.
101    BadMPEG = -211,
102}
103
104#[derive(Clone, Copy, Eq, PartialEq, Debug)]
105#[repr(i8)]
106pub enum TzSign {
107    /// West of UTC
108    West = -1,
109    /// UTC
110    UTC = 0,
111    /// East of UTC
112    East = 1,
113}
114
115// the C defined struct.
116#[derive(Clone, Copy, Debug)]
117#[repr(C)]
118pub struct XmpDateTime {
119    pub year: i32,
120    pub month: i32,
121    pub day: i32,
122    pub hour: i32,
123    pub minute: i32,
124    pub second: i32,
125    // XXX uncomment this for Exempi 2.7.0
126    // pub has_date: i8,
127    // pub has_time: i8,
128    // pub has_tz: i8,
129    pub tz_sign: TzSign,
130    pub tz_hour: i32,
131    pub tz_minute: i32,
132    pub nano_second: i32,
133}
134
135impl Default for XmpDateTime {
136    fn default() -> Self {
137        unsafe { ::std::mem::zeroed() }
138    }
139}
140
141#[repr(C)]
142pub struct XmpPacketInfo {
143    pub offset: i64,
144    pub length: i32,
145    pub pad_size: i32,
146    pub char_form: u8,
147    pub writeable: bool,
148    pub has_wrapper: bool,
149    pub pad: u8,
150}
151
152#[derive(Clone, Copy, Debug, Eq, PartialEq)]
153#[repr(u32)]
154/// Public file formats.
155pub enum FileType {
156    PDF = 0x50444620u32, /* 'PDF ' */
157    PS = 0x50532020u32,  /* 'PS  ', general PostScript following DSC
158                         conventions. */
159    EPS = 0x45505320u32, /* 'EPS ', encapsulated PostScript. */
160
161    JPEG = 0x4A504547u32,   /* 'JPEG' */
162    JPEG2K = 0x4A505820u32, /* 'JPX ', ISO 15444-1 */
163    TIFF = 0x54494646u32,   /* 'TIFF' */
164    GIF = 0x47494620u32,    /* 'GIF ' */
165    PNG = 0x504E4720u32,    /* 'PNG ' */
166    WEBP = 0x57454250u32,   /* 'WEBP' */
167
168    SWF = 0x53574620u32, /* 'SWF ' */
169    FLA = 0x464C4120u32, /* 'FLA ' */
170    FLV = 0x464C5620u32, /* 'FLV ' */
171
172    MOV = 0x4D4F5620u32,   /* 'MOV ', Quicktime */
173    AVI = 0x41564920u32,   /* 'AVI ' */
174    CIN = 0x43494E20u32,   /* 'CIN ', Cineon */
175    WAV = 0x57415620u32,   /* 'WAV ' */
176    MP3 = 0x4D503320u32,   /* 'MP3 ' */
177    SES = 0x53455320u32,   /* 'SES ', Audition session */
178    CEL = 0x43454C20u32,   /* 'CEL ', Audition loop */
179    MPEG = 0x4D504547u32,  /* 'MPEG' */
180    MPEG2 = 0x4D503220u32, /* 'MP2 ' */
181    MPEG4 = 0x4D503420u32, /* 'MP4 ', ISO 14494-12 and -14 */
182    MXF = 0x4D584620u32,   /* 'MXF ' */
183    WMAV = 0x574D4156u32,  /* 'WMAV', Windows Media Audio and Video */
184    AIFF = 0x41494646u32,  /* 'AIFF' */
185    RED = 0x52454420u32,   /* 'RED ' */
186    ARRI = 0x41525249u32,  /* 'ARRI' */
187    HEIF = 0x48454946u32,  /* 'HEIF' */
188    P2 = 0x50322020u32,    /* 'P2  ' */
189    XDCAMFam = 0x58444346u32, /* 'XDCF' */
190    XDCAMSam = 0x58444353u32, /* 'XDCS' */
191    XDCAMEx = 0x58444358u32,  /* 'XDCX' */
192    AVCHD = 0x41564844u32, /* AVHD */
193    SonyHDV = 0x53484456u32,  /* 'SHDV' */
194    CanonXF = 0x434E5846u32,  /* 'CNXF' */
195    AVCUltra = 0x41564355u32, /* 'AVCU' */
196
197    HTML = 0x48544D4Cu32, /* 'HTML' */
198    XML = 0x584D4C20u32,  /* 'XML ' */
199    TEXT = 0x74657874u32, /* 'text' */
200    SVG = 0x53564720u32,  /* 'SVG ' */
201
202    /* Adobe application file formats. */
203    Photoshop = 0x50534420u32,       /* 'PSD ' */
204    Illustrator = 0x41492020u32,     /* 'AI  ' */
205    InDesign = 0x494E4444u32,        /* 'INDD' */
206    AEProject = 0x41455020u32,       /* 'AEP ' */
207    AEProjTemplate = 0x41455420u32,  /* 'AET ', After Effects Project Template */
208    AEFilterPreset = 0x46465820u32,  /* 'FFX ' */
209    EncoreProject = 0x4E434F52u32,   /* 'NCOR' */
210    PremiereProject = 0x5052504Au32, /* 'PRPJ' */
211    PremiereTitle = 0x5052544Cu32,   /* 'PRTL' */
212    UCFFile = 0x55434620u32,         /* 'UCF ' */
213    /* Catch all. */
214    Unknown = 0x20202020u32, /* '    ' */
215}
216
217#[link(name = "exempi")]
218extern "C" {
219    pub fn xmp_init() -> bool;
220    pub fn xmp_terminate();
221
222    pub fn xmp_get_error() -> c_int;
223
224    pub fn xmp_files_new() -> *mut XmpFile;
225    pub fn xmp_files_open_new(p: *const c_char, options: u32 /*OpenFlags*/) -> *mut XmpFile;
226    pub fn xmp_files_open(
227        xf: *mut XmpFile,
228        p: *const c_char,
229        options: u32, /*OpenFlags*/
230    ) -> bool;
231    pub fn xmp_files_close(xf: *mut XmpFile, options: u32 /*CloseFlags*/) -> bool;
232
233    pub fn xmp_files_get_new_xmp(xf: *mut XmpFile) -> *mut Xmp;
234    pub fn xmp_files_get_xmp(xf: *mut XmpFile, xmp: *mut Xmp) -> bool;
235    pub fn xmp_files_get_xmp_xmpstring(
236        xf: *mut XmpFile,
237        xmp_packet: *mut XmpString,
238        packet_info: *mut XmpPacketInfo,
239    ) -> bool;
240    pub fn xmp_files_can_put_xmp(xf: *mut XmpFile, xmp: *const Xmp) -> bool;
241    pub fn xmp_files_can_put_xmp_xmpstring(xf: *mut XmpFile, xmp_packet: *const XmpString) -> bool;
242    pub fn xmp_files_can_put_xmp_cstr(
243        xf: *mut XmpFile,
244        xmp_packet: *const c_char,
245        len: size_t,
246    ) -> bool;
247
248    pub fn xmp_files_put_xmp(xf: *mut XmpFile, xmp: *const Xmp) -> bool;
249    pub fn xmp_files_put_xmp_xmpstring(xf: *mut XmpFile, xmp_packet: *const XmpString) -> bool;
250    pub fn xmp_files_put_xmp_cstr(xf: *mut XmpFile, xmp_packet: *const c_char, len: size_t)
251        -> bool;
252
253    pub fn xmp_files_free(xf: *mut XmpFile) -> bool;
254
255    pub fn xmp_files_get_file_info(
256        xf: *mut XmpFile,
257        fp: *mut XmpString,
258        options: *mut u32, /*OpenFlags*/
259        format: *mut FileType,
260        handler_flags: *mut u32, /*FormatOptionFlags*/
261    ) -> bool;
262    pub fn xmp_files_check_file_format(path: *const c_char) -> FileType;
263
264    pub fn xmp_files_get_format_info(
265        format: FileType,
266        options: *mut u32, /*FormatOptionFlags*/
267    ) -> bool;
268
269    pub fn xmp_register_namespace(
270        uri: *const c_char,
271        prefix: *const c_char,
272        reg_prefix: *mut XmpString,
273    ) -> bool;
274    pub fn xmp_namespace_prefix(ns: *const c_char, prefix: *mut XmpString) -> bool;
275    pub fn xmp_prefix_namespace_uri(prefix: *const c_char, ns: *mut XmpString) -> bool;
276
277    pub fn xmp_new_empty() -> *mut Xmp;
278    pub fn xmp_new(buffer: *const c_char, len: size_t) -> *mut Xmp;
279    pub fn xmp_copy(xmp: *const Xmp) -> *mut Xmp;
280    pub fn xmp_free(xmp: *mut Xmp) -> bool;
281    pub fn xmp_parse(xmp: *mut Xmp, buffer: *const c_char, len: size_t) -> bool;
282    pub fn xmp_serialize(
283        xmp: *const Xmp,
284        buf: *mut XmpString,
285        options: u32, /*SerialFlags*/
286        padding: u32,
287    ) -> bool;
288    pub fn xmp_serialize_and_format(
289        xmp: *const Xmp,
290        buf: *mut XmpString,
291        options: u32, /*SerialFlags*/
292        padding: u32,
293        newline: *const c_char,
294        tab: *const c_char,
295        indent: i32,
296    ) -> bool;
297
298    // get properties
299    pub fn xmp_get_property(
300        xmp: *const Xmp,
301        schema: *const c_char,
302        name: *const c_char,
303        property: *mut XmpString,
304        propsbits: *mut u32, /*PropFlags*/
305    ) -> bool;
306    pub fn xmp_get_property_date(
307        xmp: *const Xmp,
308        schema: *const c_char,
309        name: *const c_char,
310        property: *mut XmpDateTime,
311        propsbits: *mut u32, /*PropFlags*/
312    ) -> bool;
313    pub fn xmp_get_property_float(
314        xmp: *const Xmp,
315        schema: *const c_char,
316        name: *const c_char,
317        property: *mut f64,
318        propsbits: *mut u32, /*PropFlags*/
319    ) -> bool;
320    pub fn xmp_get_property_bool(
321        xmp: *const Xmp,
322        schema: *const c_char,
323        name: *const c_char,
324        property: *mut bool,
325        propsbits: *mut u32, /*PropFlags*/
326    ) -> bool;
327    pub fn xmp_get_property_int32(
328        xmp: *const Xmp,
329        schema: *const c_char,
330        name: *const c_char,
331        property: *mut i32,
332        propsbits: *mut u32, /*PropFlags*/
333    ) -> bool;
334    pub fn xmp_get_property_int64(
335        xmp: *const Xmp,
336        schema: *const c_char,
337        name: *const c_char,
338        property: *mut i64,
339        propsbits: *mut u32, /*PropFlags*/
340    ) -> bool;
341    pub fn xmp_get_array_item(
342        xmp: *const Xmp,
343        schema: *const c_char,
344        name: *const c_char,
345        index: i32,
346        property: *mut XmpString,
347        propsbits: *mut u32, /*PropFlags*/
348    ) -> bool;
349
350    // set properies
351    pub fn xmp_set_property(
352        xmp: *mut Xmp,
353        schema: *const c_char,
354        name: *const c_char,
355        value: *const c_char,
356        optionbits: u32, /*PropFlags*/
357    ) -> bool;
358    pub fn xmp_set_property_date(
359        xmp: *mut Xmp,
360        schema: *const c_char,
361        name: *const c_char,
362        value: *const XmpDateTime,
363        optionbits: u32, /*PropFlags*/
364    ) -> bool;
365    pub fn xmp_set_property_float(
366        xmp: *mut Xmp,
367        schema: *const c_char,
368        name: *const c_char,
369        value: f64,
370        optionbits: u32, /*PropFlags*/
371    ) -> bool;
372    pub fn xmp_set_property_bool(
373        xmp: *mut Xmp,
374        schema: *const c_char,
375        name: *const c_char,
376        value: bool,
377        optionbits: u32, /*PropFlags*/
378    ) -> bool;
379    pub fn xmp_set_property_int32(
380        xmp: *mut Xmp,
381        schema: *const c_char,
382        name: *const c_char,
383        value: i32,
384        optionbits: u32, /*PropFlags*/
385    ) -> bool;
386    pub fn xmp_set_property_int64(
387        xmp: *mut Xmp,
388        schema: *const c_char,
389        name: *const c_char,
390        value: i64,
391        optionbits: u32, /*PropFlags*/
392    ) -> bool;
393    pub fn xmp_set_array_item(
394        xmp: *mut Xmp,
395        schema: *const c_char,
396        name: *const c_char,
397        index: i32,
398        value: *const c_char,
399        optionbits: u32, /*PropFlags*/
400    ) -> bool;
401
402    pub fn xmp_append_array_item(
403        xmp: *mut Xmp,
404        schema: *const c_char,
405        name: *const c_char,
406        array_options: u32,
407        value: *const c_char,
408        optionbits: u32, /*PropFlags*/
409    ) -> bool;
410    pub fn xmp_delete_property(xmp: *mut Xmp, schema: *const c_char, name: *const c_char) -> bool;
411    pub fn xmp_has_property(xmp: *const Xmp, schema: *const c_char, name: *const c_char) -> bool;
412
413    pub fn xmp_get_localized_text(
414        xmp: *const Xmp,
415        schema: *const c_char,
416        name: *const c_char,
417        gen_lang: *const c_char,
418        spec_lang: *const c_char,
419        actual_lang: *mut XmpString,
420        value: *mut XmpString,
421        propbits: *mut u32, /*PropFlags*/
422    ) -> bool;
423    pub fn xmp_set_localized_text(
424        xmp: *mut Xmp,
425        schema: *const c_char,
426        name: *const c_char,
427        gen_lang: *const c_char,
428        spec_lang: *const c_char,
429        value: *const c_char,
430        optionbits: u32, /*PropFlags*/
431    ) -> bool;
432    pub fn xmp_delete_localized_text(
433        xmp: *mut Xmp,
434        schema: *const c_char,
435        name: *const c_char,
436        gen_lang: *const c_char,
437        spec_lang: *const c_char,
438    ) -> bool;
439
440    pub fn xmp_string_new() -> *mut XmpString;
441    pub fn xmp_string_free(s: *mut XmpString);
442    pub fn xmp_string_cstr(s: *const XmpString) -> *const c_char;
443    pub fn xmp_string_len(s: *const XmpString) -> size_t;
444
445    pub fn xmp_iterator_new(
446        xmp: *const Xmp,
447        schema: *const c_char,
448        name: *const c_char,
449        optionbits: u32, /*IterFlags*/
450    ) -> *mut XmpIterator;
451    pub fn xmp_iterator_free(i: *mut XmpIterator) -> bool;
452    pub fn xmp_iterator_next(
453        i: *mut XmpIterator,
454        schema: *mut XmpString,
455        name: *mut XmpString,
456        value: *mut XmpString,
457        option: *mut u32, /*IterFlags*/
458    ) -> bool;
459    pub fn xmp_iterator_skip(i: *mut XmpIterator, option: u32 /*IterSkipFlags*/) -> bool;
460
461    pub fn xmp_datetime_compare(left: *const XmpDateTime, right: *const XmpDateTime) -> c_int;
462}
463
464#[cfg(test)]
465#[test]
466fn native_call_works() {
467    let inited = unsafe { xmp_init() };
468
469    assert!(inited);
470
471    let xf = unsafe { xmp_files_new() };
472
473    assert!(!xf.is_null());
474    assert!(unsafe { xmp_files_free(xf) });
475    assert!(unsafe { xmp_get_error() } == 0);
476
477    let xmp = unsafe { xmp_new_empty() };
478    let xmpiter =
479        unsafe { xmp_iterator_new(xmp, NS_DC.as_ptr(), "keywords".as_ptr() as *const c_char, 0) };
480
481    unsafe {
482        xmp_iterator_free(xmpiter);
483    }
484    unsafe {
485        xmp_free(xmp);
486    }
487
488    let xs = unsafe { xmp_string_new() };
489    assert!(!xs.is_null());
490    let s = unsafe { xmp_string_cstr(xs) };
491    assert!(!s.is_null());
492    unsafe {
493        xmp_string_free(xs);
494    }
495
496    unsafe {
497        xmp_terminate();
498    }
499}