exempi_sys/
lib.rs

1//
2// Copyright (c) 2016-2023, 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    pub has_date: i8,
126    pub has_time: i8,
127    pub has_tz: i8,
128    pub tz_sign: TzSign,
129    pub tz_hour: i32,
130    pub tz_minute: i32,
131    pub nano_second: i32,
132}
133
134impl Default for XmpDateTime {
135    fn default() -> Self {
136        unsafe { ::std::mem::zeroed() }
137    }
138}
139
140#[repr(C)]
141pub struct XmpPacketInfo {
142    pub offset: i64,
143    pub length: i32,
144    pub pad_size: i32,
145    pub char_form: u8,
146    pub writeable: bool,
147    pub has_wrapper: bool,
148    pub pad: u8,
149}
150
151#[derive(Clone, Copy, Debug, Eq, PartialEq)]
152#[repr(u32)]
153/// Public file formats.
154pub enum FileType {
155    PDF = 0x50444620u32, /* 'PDF ' */
156    PS = 0x50532020u32,  /* 'PS  ', general PostScript following DSC
157                         conventions. */
158    EPS = 0x45505320u32, /* 'EPS ', encapsulated PostScript. */
159
160    JPEG = 0x4A504547u32,   /* 'JPEG' */
161    JPEG2K = 0x4A505820u32, /* 'JPX ', ISO 15444-1 */
162    TIFF = 0x54494646u32,   /* 'TIFF' */
163    GIF = 0x47494620u32,    /* 'GIF ' */
164    PNG = 0x504E4720u32,    /* 'PNG ' */
165    WEBP = 0x57454250u32,   /* 'WEBP' */
166
167    SWF = 0x53574620u32, /* 'SWF ' */
168    FLA = 0x464C4120u32, /* 'FLA ' */
169    FLV = 0x464C5620u32, /* 'FLV ' */
170
171    MOV = 0x4D4F5620u32,   /* 'MOV ', Quicktime */
172    AVI = 0x41564920u32,   /* 'AVI ' */
173    CIN = 0x43494E20u32,   /* 'CIN ', Cineon */
174    WAV = 0x57415620u32,   /* 'WAV ' */
175    MP3 = 0x4D503320u32,   /* 'MP3 ' */
176    SES = 0x53455320u32,   /* 'SES ', Audition session */
177    CEL = 0x43454C20u32,   /* 'CEL ', Audition loop */
178    MPEG = 0x4D504547u32,  /* 'MPEG' */
179    MPEG2 = 0x4D503220u32, /* 'MP2 ' */
180    MPEG4 = 0x4D503420u32, /* 'MP4 ', ISO 14494-12 and -14 */
181    MXF = 0x4D584620u32,   /* 'MXF ' */
182    WMAV = 0x574D4156u32,  /* 'WMAV', Windows Media Audio and Video */
183    AIFF = 0x41494646u32,  /* 'AIFF' */
184    RED = 0x52454420u32,   /* 'RED ' */
185    ARRI = 0x41525249u32,  /* 'ARRI' */
186    HEIF = 0x48454946u32,  /* 'HEIF' */
187    P2 = 0x50322020u32,    /* 'P2  ' */
188    XDCAMFam = 0x58444346u32, /* 'XDCF' */
189    XDCAMSam = 0x58444353u32, /* 'XDCS' */
190    XDCAMEx = 0x58444358u32,  /* 'XDCX' */
191    AVCHD = 0x41564844u32, /* AVHD */
192    SonyHDV = 0x53484456u32,  /* 'SHDV' */
193    CanonXF = 0x434E5846u32,  /* 'CNXF' */
194    AVCUltra = 0x41564355u32, /* 'AVCU' */
195
196    HTML = 0x48544D4Cu32, /* 'HTML' */
197    XML = 0x584D4C20u32,  /* 'XML ' */
198    TEXT = 0x74657874u32, /* 'text' */
199    SVG = 0x53564720u32,  /* 'SVG ' */
200
201    /* Adobe application file formats. */
202    Photoshop = 0x50534420u32,       /* 'PSD ' */
203    Illustrator = 0x41492020u32,     /* 'AI  ' */
204    InDesign = 0x494E4444u32,        /* 'INDD' */
205    AEProject = 0x41455020u32,       /* 'AEP ' */
206    AEProjTemplate = 0x41455420u32,  /* 'AET ', After Effects Project Template */
207    AEFilterPreset = 0x46465820u32,  /* 'FFX ' */
208    EncoreProject = 0x4E434F52u32,   /* 'NCOR' */
209    PremiereProject = 0x5052504Au32, /* 'PRPJ' */
210    PremiereTitle = 0x5052544Cu32,   /* 'PRTL' */
211    UCFFile = 0x55434620u32,         /* 'UCF ' */
212    /* Catch all. */
213    Unknown = 0x20202020u32, /* '    ' */
214}
215
216#[link(name = "exempi")]
217extern "C" {
218    pub fn xmp_init() -> bool;
219    pub fn xmp_terminate();
220
221    pub fn xmp_get_error() -> c_int;
222
223    pub fn xmp_files_new() -> *mut XmpFile;
224    pub fn xmp_files_open_new(p: *const c_char, options: u32 /*OpenFlags*/) -> *mut XmpFile;
225    pub fn xmp_files_open(
226        xf: *mut XmpFile,
227        p: *const c_char,
228        options: u32, /*OpenFlags*/
229    ) -> bool;
230    pub fn xmp_files_close(xf: *mut XmpFile, options: u32 /*CloseFlags*/) -> bool;
231
232    pub fn xmp_files_get_new_xmp(xf: *mut XmpFile) -> *mut Xmp;
233    pub fn xmp_files_get_xmp(xf: *mut XmpFile, xmp: *mut Xmp) -> bool;
234    pub fn xmp_files_get_xmp_xmpstring(
235        xf: *mut XmpFile,
236        xmp_packet: *mut XmpString,
237        packet_info: *mut XmpPacketInfo,
238    ) -> bool;
239    pub fn xmp_files_can_put_xmp(xf: *mut XmpFile, xmp: *const Xmp) -> bool;
240    pub fn xmp_files_can_put_xmp_xmpstring(xf: *mut XmpFile, xmp_packet: *const XmpString) -> bool;
241    pub fn xmp_files_can_put_xmp_cstr(
242        xf: *mut XmpFile,
243        xmp_packet: *const c_char,
244        len: size_t,
245    ) -> bool;
246
247    pub fn xmp_files_put_xmp(xf: *mut XmpFile, xmp: *const Xmp) -> bool;
248    pub fn xmp_files_put_xmp_xmpstring(xf: *mut XmpFile, xmp_packet: *const XmpString) -> bool;
249    pub fn xmp_files_put_xmp_cstr(xf: *mut XmpFile, xmp_packet: *const c_char, len: size_t)
250        -> bool;
251
252    pub fn xmp_files_free(xf: *mut XmpFile) -> bool;
253
254    pub fn xmp_files_get_file_info(
255        xf: *mut XmpFile,
256        fp: *mut XmpString,
257        options: *mut u32, /*OpenFlags*/
258        format: *mut FileType,
259        handler_flags: *mut u32, /*FormatOptionFlags*/
260    ) -> bool;
261    pub fn xmp_files_check_file_format(path: *const c_char) -> FileType;
262
263    pub fn xmp_files_get_format_info(
264        format: FileType,
265        options: *mut u32, /*FormatOptionFlags*/
266    ) -> bool;
267
268    pub fn xmp_register_namespace(
269        uri: *const c_char,
270        prefix: *const c_char,
271        reg_prefix: *mut XmpString,
272    ) -> bool;
273    pub fn xmp_namespace_prefix(ns: *const c_char, prefix: *mut XmpString) -> bool;
274    pub fn xmp_prefix_namespace_uri(prefix: *const c_char, ns: *mut XmpString) -> bool;
275
276    pub fn xmp_new_empty() -> *mut Xmp;
277    pub fn xmp_new(buffer: *const c_char, len: size_t) -> *mut Xmp;
278    pub fn xmp_copy(xmp: *const Xmp) -> *mut Xmp;
279    pub fn xmp_free(xmp: *mut Xmp) -> bool;
280    pub fn xmp_parse(xmp: *mut Xmp, buffer: *const c_char, len: size_t) -> bool;
281    pub fn xmp_serialize(
282        xmp: *const Xmp,
283        buf: *mut XmpString,
284        options: u32, /*SerialFlags*/
285        padding: u32,
286    ) -> bool;
287    pub fn xmp_serialize_and_format(
288        xmp: *const Xmp,
289        buf: *mut XmpString,
290        options: u32, /*SerialFlags*/
291        padding: u32,
292        newline: *const c_char,
293        tab: *const c_char,
294        indent: i32,
295    ) -> bool;
296
297    // get properties
298    pub fn xmp_get_property(
299        xmp: *const Xmp,
300        schema: *const c_char,
301        name: *const c_char,
302        property: *mut XmpString,
303        propsbits: *mut u32, /*PropFlags*/
304    ) -> bool;
305    pub fn xmp_get_property_date(
306        xmp: *const Xmp,
307        schema: *const c_char,
308        name: *const c_char,
309        property: *mut XmpDateTime,
310        propsbits: *mut u32, /*PropFlags*/
311    ) -> bool;
312    pub fn xmp_get_property_float(
313        xmp: *const Xmp,
314        schema: *const c_char,
315        name: *const c_char,
316        property: *mut f64,
317        propsbits: *mut u32, /*PropFlags*/
318    ) -> bool;
319    pub fn xmp_get_property_bool(
320        xmp: *const Xmp,
321        schema: *const c_char,
322        name: *const c_char,
323        property: *mut bool,
324        propsbits: *mut u32, /*PropFlags*/
325    ) -> bool;
326    pub fn xmp_get_property_int32(
327        xmp: *const Xmp,
328        schema: *const c_char,
329        name: *const c_char,
330        property: *mut i32,
331        propsbits: *mut u32, /*PropFlags*/
332    ) -> bool;
333    pub fn xmp_get_property_int64(
334        xmp: *const Xmp,
335        schema: *const c_char,
336        name: *const c_char,
337        property: *mut i64,
338        propsbits: *mut u32, /*PropFlags*/
339    ) -> bool;
340    pub fn xmp_get_array_item(
341        xmp: *const Xmp,
342        schema: *const c_char,
343        name: *const c_char,
344        index: i32,
345        property: *mut XmpString,
346        propsbits: *mut u32, /*PropFlags*/
347    ) -> bool;
348
349    // set properies
350    pub fn xmp_set_property(
351        xmp: *mut Xmp,
352        schema: *const c_char,
353        name: *const c_char,
354        value: *const c_char,
355        optionbits: u32, /*PropFlags*/
356    ) -> bool;
357    pub fn xmp_set_property_date(
358        xmp: *mut Xmp,
359        schema: *const c_char,
360        name: *const c_char,
361        value: *const XmpDateTime,
362        optionbits: u32, /*PropFlags*/
363    ) -> bool;
364    pub fn xmp_set_property_float(
365        xmp: *mut Xmp,
366        schema: *const c_char,
367        name: *const c_char,
368        value: f64,
369        optionbits: u32, /*PropFlags*/
370    ) -> bool;
371    pub fn xmp_set_property_bool(
372        xmp: *mut Xmp,
373        schema: *const c_char,
374        name: *const c_char,
375        value: bool,
376        optionbits: u32, /*PropFlags*/
377    ) -> bool;
378    pub fn xmp_set_property_int32(
379        xmp: *mut Xmp,
380        schema: *const c_char,
381        name: *const c_char,
382        value: i32,
383        optionbits: u32, /*PropFlags*/
384    ) -> bool;
385    pub fn xmp_set_property_int64(
386        xmp: *mut Xmp,
387        schema: *const c_char,
388        name: *const c_char,
389        value: i64,
390        optionbits: u32, /*PropFlags*/
391    ) -> bool;
392    pub fn xmp_set_array_item(
393        xmp: *mut Xmp,
394        schema: *const c_char,
395        name: *const c_char,
396        index: i32,
397        value: *const c_char,
398        optionbits: u32, /*PropFlags*/
399    ) -> bool;
400
401    pub fn xmp_append_array_item(
402        xmp: *mut Xmp,
403        schema: *const c_char,
404        name: *const c_char,
405        array_options: u32,
406        value: *const c_char,
407        optionbits: u32, /*PropFlags*/
408    ) -> bool;
409    pub fn xmp_delete_property(xmp: *mut Xmp, schema: *const c_char, name: *const c_char) -> bool;
410    pub fn xmp_has_property(xmp: *const Xmp, schema: *const c_char, name: *const c_char) -> bool;
411
412    pub fn xmp_get_localized_text(
413        xmp: *const Xmp,
414        schema: *const c_char,
415        name: *const c_char,
416        gen_lang: *const c_char,
417        spec_lang: *const c_char,
418        actual_lang: *mut XmpString,
419        value: *mut XmpString,
420        propbits: *mut u32, /*PropFlags*/
421    ) -> bool;
422    pub fn xmp_set_localized_text(
423        xmp: *mut Xmp,
424        schema: *const c_char,
425        name: *const c_char,
426        gen_lang: *const c_char,
427        spec_lang: *const c_char,
428        value: *const c_char,
429        optionbits: u32, /*PropFlags*/
430    ) -> bool;
431    pub fn xmp_delete_localized_text(
432        xmp: *mut Xmp,
433        schema: *const c_char,
434        name: *const c_char,
435        gen_lang: *const c_char,
436        spec_lang: *const c_char,
437    ) -> bool;
438
439    pub fn xmp_string_new() -> *mut XmpString;
440    pub fn xmp_string_free(s: *mut XmpString);
441    pub fn xmp_string_cstr(s: *const XmpString) -> *const c_char;
442    pub fn xmp_string_len(s: *const XmpString) -> size_t;
443
444    pub fn xmp_iterator_new(
445        xmp: *const Xmp,
446        schema: *const c_char,
447        name: *const c_char,
448        optionbits: u32, /*IterFlags*/
449    ) -> *mut XmpIterator;
450    pub fn xmp_iterator_free(i: *mut XmpIterator) -> bool;
451    pub fn xmp_iterator_next(
452        i: *mut XmpIterator,
453        schema: *mut XmpString,
454        name: *mut XmpString,
455        value: *mut XmpString,
456        option: *mut u32, /*IterFlags*/
457    ) -> bool;
458    pub fn xmp_iterator_skip(i: *mut XmpIterator, option: u32 /*IterSkipFlags*/) -> bool;
459
460    pub fn xmp_datetime_compare(left: *const XmpDateTime, right: *const XmpDateTime) -> c_int;
461}
462
463#[cfg(test)]
464#[test]
465fn native_call_works() {
466    let inited = unsafe { xmp_init() };
467
468    assert!(inited);
469
470    let xf = unsafe { xmp_files_new() };
471
472    assert!(!xf.is_null());
473    assert!(unsafe { xmp_files_free(xf) });
474    assert!(unsafe { xmp_get_error() } == 0);
475
476    let xmp = unsafe { xmp_new_empty() };
477    let xmpiter =
478        unsafe { xmp_iterator_new(xmp, NS_DC.as_ptr(), "keywords".as_ptr() as *const c_char, 0) };
479
480    unsafe {
481        xmp_iterator_free(xmpiter);
482    }
483    unsafe {
484        xmp_free(xmp);
485    }
486
487    let xs = unsafe { xmp_string_new() };
488    assert!(!xs.is_null());
489    let s = unsafe { xmp_string_cstr(xs) };
490    assert!(!s.is_null());
491    unsafe {
492        xmp_string_free(xs);
493    }
494
495    unsafe {
496        xmp_terminate();
497    }
498}