1 /*
2 * exempi - exempi.cpp
3 *
4 * Copyright (C) 2007-2019 Hubert Figuière
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1 Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2 Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the
17 * distribution.
18 *
19 * 3 Neither the name of the Authors, nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software wit hout specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 * OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
37 /** @brief this file implement the glue for XMP API
38 */
39
40 #include "xmpconsts.h"
41 #include "xmp.h"
42 #include "xmperrors.h"
43
44 #include <string>
45 #include <iostream>
46 #include <memory>
47
48 #define XMP_INCLUDE_XMPFILES 1
49 #define TXMP_STRING_TYPE std::string
50 #include "XMP.hpp"
51 #include "XMP.incl_cpp"
52 #include "XMPUtils.hpp"
53
54 /*
55 * Use this to mark a symbol to be exported
56 */
57 #define API_EXPORT __attribute__ ((visibility ("default")))
58
59 #if HAVE_NATIVE_TLS
60
61 static TLS int g_error = 0;
62
set_error(int err)63 static void set_error(int err)
64 {
65 g_error = err;
66 }
67
68 #else
69
70 #include <pthread.h>
71
72 /* Portable thread local storage using pthreads */
73 static pthread_key_t key = NULL;
74 static pthread_once_t key_once = PTHREAD_ONCE_INIT;
75
76 /* Destructor called when a thread exits - ensure to delete allocated int
77 * pointer */
destroy_tls_key(void * ptr)78 static void destroy_tls_key(void *ptr)
79 {
80 int *err_ptr = static_cast<int *>(ptr);
81 delete err_ptr;
82 }
83
84 /* Create a key for use with pthreads local storage */
create_tls_key()85 static void create_tls_key()
86 {
87 (void)pthread_key_create(&key, destroy_tls_key);
88 }
89
90 /* Obtain the latest xmp error for this specific thread - defaults to 0 */
get_error_for_thread()91 static int get_error_for_thread()
92 {
93 int *err_ptr;
94
95 pthread_once(&key_once, create_tls_key);
96 err_ptr = (int *)pthread_getspecific(key);
97
98 if (err_ptr == NULL) {
99 return 0;
100 }
101
102 return *err_ptr;
103 }
104
105 /* set the current xmp error for this specific thread */
set_error(int err)106 static void set_error(int err)
107 {
108 int *err_ptr;
109
110 // Ensure that create_thread_local_storage_key is only called
111 // once, by the first thread, to create the key.
112 pthread_once(&key_once, create_tls_key);
113
114 // Retrieve pointer to int for this thread.
115 err_ptr = (int *)pthread_getspecific(key);
116
117 // Allocate it, if it does not exists.
118 if (err_ptr == NULL) {
119 err_ptr = new int;
120 pthread_setspecific(key, err_ptr);
121 }
122
123 // Save the error for this thread.
124 *err_ptr = err;
125 }
126
127 #endif
128
set_error(const XMP_Error & e)129 static void set_error(const XMP_Error &e)
130 {
131 set_error(-e.GetID());
132 std::cerr << e.GetErrMsg() << std::endl;
133 }
134
135 #define RESET_ERROR set_error(0)
136
137 // Hack: assign between XMP_DateTime and XmpDateTime
138 #define ASSIGN(dst, src) \
139 (dst).year = (src).year; \
140 (dst).month = (src).month; \
141 (dst).day = (src).day; \
142 (dst).hour = (src).hour; \
143 (dst).minute = (src).minute; \
144 (dst).second = (src).second; \
145 (dst).tzSign = (src).tzSign; \
146 (dst).tzHour = (src).tzHour; \
147 (dst).tzMinute = (src).tzMinute; \
148 (dst).nanoSecond = (src).nanoSecond;
149
150 #ifdef __cplusplus
151 extern "C" {
152 #endif
153
154 API_EXPORT extern const char NS_XMP_META[] = "adobe:ns:meta/";
155 API_EXPORT extern const char NS_RDF[] = kXMP_NS_RDF;
156 API_EXPORT extern const char NS_EXIF[] = kXMP_NS_EXIF;
157 API_EXPORT extern const char NS_TIFF[] = kXMP_NS_TIFF;
158 API_EXPORT extern const char NS_XAP[] = kXMP_NS_XMP;
159 API_EXPORT extern const char NS_XAP_RIGHTS[] = kXMP_NS_XMP_Rights;
160 API_EXPORT extern const char NS_DC[] = kXMP_NS_DC;
161 API_EXPORT extern const char NS_EXIF_AUX[] = kXMP_NS_EXIF_Aux;
162 API_EXPORT extern const char NS_CRS[] = kXMP_NS_CameraRaw;
163 API_EXPORT extern const char NS_LIGHTROOM[] = "http://ns.adobe.com/lightroom/1.0/";
164 API_EXPORT extern const char NS_CAMERA_RAW_SETTINGS[] = kXMP_NS_CameraRaw;
165 API_EXPORT extern const char NS_CAMERA_RAW_SAVED_SETTINGS[] =
166 "http://ns.adobe.com/camera-raw-saved-settings/1.0/";
167 API_EXPORT extern const char NS_PHOTOSHOP[] = kXMP_NS_Photoshop;
168 API_EXPORT extern const char NS_IPTC4XMP[] = kXMP_NS_IPTCCore;
169 API_EXPORT extern const char NS_TPG[] = kXMP_NS_XMP_PagedFile;
170 API_EXPORT extern const char NS_DIMENSIONS_TYPE[] = kXMP_NS_XMP_Dimensions;
171 API_EXPORT extern const char NS_CC[] = "http://creativecommons.org/ns#";
172 API_EXPORT extern const char NS_PDF[] = kXMP_NS_PDF;
173 API_EXPORT extern const char NS_XML[] = kXMP_NS_XML;
174
175 #define STRING(x) reinterpret_cast<std::string *>(x)
176
177 #define CHECK_PTR(p, r) \
178 if (p == NULL) { \
179 set_error(XMPErr_BadObject); \
180 return r; \
181 }
182
183 API_EXPORT
xmp_get_error()184 int xmp_get_error()
185 {
186 #if HAVE_NATIVE_TLS
187 return g_error;
188 #else
189 return get_error_for_thread();
190 #endif
191 }
192
193 // the error callback - force throwing exceptions
_xmp_error_callback(void *,XMP_ErrorSeverity,XMP_Int32,XMP_StringPtr)194 static bool _xmp_error_callback(void* /*context*/, XMP_ErrorSeverity /*severity*/,
195 XMP_Int32 /*cause*/, XMP_StringPtr /*message*/)
196 {
197 return false;
198 }
199
200 API_EXPORT
xmp_init()201 bool xmp_init()
202 {
203 RESET_ERROR;
204 try {
205 // no need to initialize anything else.
206 // XMP SDK 5.1.2 needs this because it has been stripped off local
207 // text conversion the one that was done in Exempi with libiconv.
208 bool result = SXMPFiles::Initialize(kXMPFiles_IgnoreLocalText);
209 SXMPMeta::SetDefaultErrorCallback(&_xmp_error_callback, nullptr, 1);
210 return result;
211 }
212 catch (const XMP_Error &e) {
213 set_error(e);
214 }
215 return false;
216 }
217
218 API_EXPORT
xmp_terminate()219 void xmp_terminate()
220 {
221 RESET_ERROR;
222 SXMPFiles::Terminate();
223 }
224
225 API_EXPORT
xmp_register_namespace(const char * namespaceURI,const char * suggestedPrefix,XmpStringPtr registeredPrefix)226 bool xmp_register_namespace(const char *namespaceURI,
227 const char *suggestedPrefix,
228 XmpStringPtr registeredPrefix)
229 {
230 RESET_ERROR;
231 try {
232 return SXMPMeta::RegisterNamespace(namespaceURI, suggestedPrefix,
233 STRING(registeredPrefix));
234 }
235 catch (const XMP_Error &e) {
236 set_error(e);
237 }
238 return false;
239 }
240
241 API_EXPORT
xmp_namespace_prefix(const char * ns,XmpStringPtr prefix)242 bool xmp_namespace_prefix(const char *ns, XmpStringPtr prefix)
243 {
244 CHECK_PTR(ns, false);
245 RESET_ERROR;
246 try {
247 return SXMPMeta::GetNamespacePrefix(ns, STRING(prefix));
248 }
249 catch (const XMP_Error &e) {
250 set_error(e);
251 }
252 return false;
253 }
254
255 API_EXPORT
xmp_prefix_namespace_uri(const char * prefix,XmpStringPtr ns)256 bool xmp_prefix_namespace_uri(const char *prefix, XmpStringPtr ns)
257 {
258 CHECK_PTR(prefix, false);
259 RESET_ERROR;
260 try {
261 return SXMPMeta::GetNamespaceURI(prefix, STRING(ns));
262 }
263 catch (const XMP_Error &e) {
264 set_error(e);
265 }
266 return false;
267 }
268
269 API_EXPORT
xmp_files_new()270 XmpFilePtr xmp_files_new()
271 {
272 RESET_ERROR;
273
274 try {
275 auto txf = std::unique_ptr<SXMPFiles>(new SXMPFiles());
276
277 return reinterpret_cast<XmpFilePtr>(txf.release());
278 }
279 catch (const XMP_Error &e) {
280 set_error(e);
281 }
282 return NULL;
283 }
284
285 API_EXPORT
xmp_files_open_new(const char * path,XmpOpenFileOptions options)286 XmpFilePtr xmp_files_open_new(const char *path, XmpOpenFileOptions options)
287 {
288 CHECK_PTR(path, NULL);
289 RESET_ERROR;
290
291 try {
292 auto txf = std::unique_ptr<SXMPFiles>(new SXMPFiles);
293
294 txf->OpenFile(path, XMP_FT_UNKNOWN, options);
295
296 return reinterpret_cast<XmpFilePtr>(txf.release());
297 }
298 catch (const XMP_Error &e) {
299 set_error(e);
300 }
301
302 return NULL;
303 }
304
305 API_EXPORT
xmp_files_open(XmpFilePtr xf,const char * path,XmpOpenFileOptions options)306 bool xmp_files_open(XmpFilePtr xf, const char *path, XmpOpenFileOptions options)
307 {
308 CHECK_PTR(xf, false);
309 RESET_ERROR;
310 auto txf = reinterpret_cast<SXMPFiles *>(xf);
311 try {
312 return txf->OpenFile(path, XMP_FT_UNKNOWN, options);
313 }
314 catch (const XMP_Error &e) {
315 set_error(e);
316 }
317 return false;
318 }
319
320 API_EXPORT
xmp_files_close(XmpFilePtr xf,XmpCloseFileOptions options)321 bool xmp_files_close(XmpFilePtr xf, XmpCloseFileOptions options)
322 {
323 CHECK_PTR(xf, false);
324 RESET_ERROR;
325 try {
326 auto txf = reinterpret_cast<SXMPFiles *>(xf);
327 txf->CloseFile(options);
328 }
329 catch (const XMP_Error &e) {
330 set_error(e);
331 return false;
332 }
333 return true;
334 }
335
336 API_EXPORT
xmp_files_get_new_xmp(XmpFilePtr xf)337 XmpPtr xmp_files_get_new_xmp(XmpFilePtr xf)
338 {
339 CHECK_PTR(xf, NULL);
340 RESET_ERROR;
341 auto txf = reinterpret_cast<SXMPFiles *>(xf);
342
343 bool result = false;
344 try {
345 auto xmp = std::unique_ptr<SXMPMeta>(new SXMPMeta);
346 result = txf->GetXMP(xmp.get());
347 if (result) {
348 return reinterpret_cast<XmpPtr>(xmp.release());
349 }
350 }
351 catch (const XMP_Error &e) {
352 set_error(e);
353 }
354 return NULL;
355 }
356
357 API_EXPORT
xmp_files_get_xmp(XmpFilePtr xf,XmpPtr xmp)358 bool xmp_files_get_xmp(XmpFilePtr xf, XmpPtr xmp)
359 {
360 CHECK_PTR(xf, false);
361 CHECK_PTR(xmp, false);
362 RESET_ERROR;
363 bool result = false;
364 try {
365 auto txf = reinterpret_cast<SXMPFiles *>(xf);
366
367 result = txf->GetXMP(reinterpret_cast<SXMPMeta *>(xmp));
368 }
369 catch (const XMP_Error &e) {
370 set_error(e);
371 }
372 return result;
373 }
374
375 API_EXPORT
xmp_files_get_xmp_xmpstring(XmpFilePtr xf,XmpStringPtr xmp_packet,XmpPacketInfo * packet_info)376 bool xmp_files_get_xmp_xmpstring(XmpFilePtr xf, XmpStringPtr xmp_packet,
377 XmpPacketInfo* packet_info)
378 {
379 CHECK_PTR(xf, false);
380 CHECK_PTR(xmp_packet, false);
381 RESET_ERROR;
382 bool result = false;
383 try {
384 SXMPFiles *txf = reinterpret_cast<SXMPFiles*>(xf);
385
386 XMP_PacketInfo xmp_packet_info;
387 result = txf->GetXMP(NULL,
388 reinterpret_cast<std::string*>(xmp_packet),
389 &xmp_packet_info);
390 if (packet_info) {
391 packet_info->offset = xmp_packet_info.offset;
392 packet_info->length = xmp_packet_info.length;
393 packet_info->padSize = xmp_packet_info.padSize;
394 packet_info->charForm = xmp_packet_info.charForm;
395 packet_info->writeable = xmp_packet_info.writeable;
396 packet_info->hasWrapper = xmp_packet_info.hasWrapper;
397 packet_info->pad = xmp_packet_info.pad;
398 }
399 }
400 catch(const XMP_Error & e) {
401 set_error(e);
402 }
403 return result;
404 }
405
406
407 API_EXPORT
xmp_files_can_put_xmp(XmpFilePtr xf,XmpPtr xmp)408 bool xmp_files_can_put_xmp(XmpFilePtr xf, XmpPtr xmp)
409 {
410 CHECK_PTR(xf, false);
411 RESET_ERROR;
412 auto txf = reinterpret_cast<SXMPFiles *>(xf);
413 bool result = false;
414
415 try {
416 result = txf->CanPutXMP(*reinterpret_cast<const SXMPMeta *>(xmp));
417 }
418 catch (const XMP_Error &e) {
419 set_error(e);
420 return false;
421 }
422 return result;
423 }
424
425 API_EXPORT
xmp_files_can_put_xmp_xmpstring(XmpFilePtr xf,XmpStringPtr xmp_packet)426 bool xmp_files_can_put_xmp_xmpstring(XmpFilePtr xf, XmpStringPtr xmp_packet)
427 {
428 CHECK_PTR(xf, false);
429 RESET_ERROR;
430 SXMPFiles *txf = reinterpret_cast<SXMPFiles*>(xf);
431 bool result = false;
432
433 try {
434 result = txf->CanPutXMP(*reinterpret_cast<const std::string*>(xmp_packet));
435 }
436 catch(const XMP_Error & e) {
437 set_error(e);
438 return false;
439 }
440 return result;
441 }
442
443 API_EXPORT
xmp_files_can_put_xmp_cstr(XmpFilePtr xf,const char * xmp_packet,size_t len)444 bool xmp_files_can_put_xmp_cstr(XmpFilePtr xf, const char* xmp_packet, size_t len)
445 {
446 CHECK_PTR(xf, false);
447 RESET_ERROR;
448 SXMPFiles *txf = reinterpret_cast<SXMPFiles*>(xf);
449 bool result = false;
450
451 try {
452 result = txf->CanPutXMP(xmp_packet, len);
453 }
454 catch(const XMP_Error & e) {
455 set_error(e);
456 return false;
457 }
458 return result;
459 }
460
461 API_EXPORT
xmp_files_put_xmp(XmpFilePtr xf,XmpPtr xmp)462 bool xmp_files_put_xmp(XmpFilePtr xf, XmpPtr xmp)
463 {
464 CHECK_PTR(xf, false);
465 CHECK_PTR(xmp, false);
466 RESET_ERROR;
467 auto txf = reinterpret_cast<SXMPFiles *>(xf);
468
469 try {
470 txf->PutXMP(*reinterpret_cast<const SXMPMeta *>(xmp));
471 }
472 catch (const XMP_Error &e) {
473 set_error(e);
474 return false;
475 }
476 return true;
477 }
478
479 API_EXPORT
xmp_files_put_xmp_xmpstring(XmpFilePtr xf,XmpStringPtr xmp_packet)480 bool xmp_files_put_xmp_xmpstring(XmpFilePtr xf, XmpStringPtr xmp_packet)
481 {
482 CHECK_PTR(xf, false);
483 CHECK_PTR(xmp_packet, false);
484 RESET_ERROR;
485 SXMPFiles *txf = reinterpret_cast<SXMPFiles*>(xf);
486
487 try {
488 txf->PutXMP(*reinterpret_cast<const std::string*>(xmp_packet));
489 }
490 catch(const XMP_Error & e) {
491 set_error(e);
492 return false;
493 }
494 return true;
495 }
496
497 API_EXPORT
xmp_files_put_xmp_cstr(XmpFilePtr xf,const char * xmp_packet,size_t len)498 bool xmp_files_put_xmp_cstr(XmpFilePtr xf, const char* xmp_packet, size_t len)
499 {
500 CHECK_PTR(xf, false);
501 CHECK_PTR(xmp_packet, false);
502 RESET_ERROR;
503 SXMPFiles *txf = reinterpret_cast<SXMPFiles*>(xf);
504
505 try {
506 txf->PutXMP(xmp_packet, len);
507 }
508 catch(const XMP_Error & e) {
509 set_error(e);
510 return false;
511 }
512 return true;
513 }
514
515 API_EXPORT
xmp_files_get_file_info(XmpFilePtr xf,XmpStringPtr filePath,XmpOpenFileOptions * options,XmpFileType * file_format,XmpFileFormatOptions * handler_flags)516 bool xmp_files_get_file_info(XmpFilePtr xf, XmpStringPtr filePath,
517 XmpOpenFileOptions *options,
518 XmpFileType *file_format,
519 XmpFileFormatOptions *handler_flags)
520 {
521 CHECK_PTR(xf, false);
522 RESET_ERROR;
523
524 bool result = false;
525 auto txf = reinterpret_cast<SXMPFiles *>(xf);
526 try {
527 result = txf->GetFileInfo(STRING(filePath), (XMP_OptionBits *)options,
528 (XMP_FileFormat *)file_format,
529 (XMP_OptionBits *)handler_flags);
530 }
531 catch (const XMP_Error &e) {
532 set_error(e);
533 return false;
534 }
535
536 return result;
537 }
538
539 API_EXPORT
xmp_files_free(XmpFilePtr xf)540 bool xmp_files_free(XmpFilePtr xf)
541 {
542 CHECK_PTR(xf, false);
543 RESET_ERROR;
544 auto txf = reinterpret_cast<SXMPFiles *>(xf);
545 try {
546 delete txf;
547 }
548 catch (const XMP_Error &e) {
549 set_error(e);
550 return false;
551 }
552 return true;
553 }
554
555 API_EXPORT
xmp_files_get_format_info(XmpFileType format,XmpFileFormatOptions * options)556 bool xmp_files_get_format_info(XmpFileType format,
557 XmpFileFormatOptions *options)
558 {
559 RESET_ERROR;
560
561 bool result = false;
562 try {
563 result = SXMPFiles::GetFormatInfo(format, (XMP_OptionBits *)options);
564 }
565 catch (const XMP_Error &e) {
566 set_error(e);
567 return false;
568 }
569 return result;
570 }
571
572 API_EXPORT
xmp_files_check_file_format(const char * filePath)573 XmpFileType xmp_files_check_file_format(const char *filePath)
574 {
575 CHECK_PTR(filePath, XMP_FT_UNKNOWN);
576 RESET_ERROR;
577
578 XmpFileType file_type = XMP_FT_UNKNOWN;
579 try {
580 file_type = (XmpFileType)SXMPFiles::CheckFileFormat(filePath);
581 }
582 catch (const XMP_Error &e) {
583 set_error(e);
584 return XMP_FT_UNKNOWN;
585 }
586 return file_type;
587 }
588
589 API_EXPORT
xmp_new_empty()590 XmpPtr xmp_new_empty()
591 {
592 RESET_ERROR;
593 SXMPMeta *txmp = new SXMPMeta;
594 return (XmpPtr)txmp;
595 }
596
597 API_EXPORT
xmp_new(const char * buffer,size_t len)598 XmpPtr xmp_new(const char *buffer, size_t len)
599 {
600 CHECK_PTR(buffer, NULL);
601 RESET_ERROR;
602
603 try {
604 auto txmp = std::unique_ptr<SXMPMeta>(new SXMPMeta(buffer, len));
605 return reinterpret_cast<XmpPtr>(txmp.release());
606 }
607 catch (const XMP_Error &e) {
608 set_error(e);
609 }
610 return NULL;
611 }
612
613 API_EXPORT
xmp_copy(XmpPtr xmp)614 XmpPtr xmp_copy(XmpPtr xmp)
615 {
616 CHECK_PTR(xmp, NULL);
617 RESET_ERROR;
618
619 try {
620 auto txmp = std::unique_ptr<SXMPMeta>(new SXMPMeta(*(SXMPMeta *)xmp));
621 return reinterpret_cast<XmpPtr>(txmp.release());
622 }
623 catch (const XMP_Error &e) {
624 set_error(e);
625 }
626 return NULL;
627 }
628
629 API_EXPORT
xmp_parse(XmpPtr xmp,const char * buffer,size_t len)630 bool xmp_parse(XmpPtr xmp, const char *buffer, size_t len)
631 {
632 CHECK_PTR(xmp, false);
633 CHECK_PTR(buffer, false);
634
635 SXMPMeta *txmp = (SXMPMeta *)xmp;
636 try {
637 txmp->ParseFromBuffer(buffer, len, kXMP_RequireXMPMeta);
638 }
639 catch (const XMP_Error &e) {
640 set_error(e);
641 return false;
642 }
643 return true;
644 }
645
646 API_EXPORT
xmp_serialize(XmpPtr xmp,XmpStringPtr buffer,uint32_t options,uint32_t padding)647 bool xmp_serialize(XmpPtr xmp, XmpStringPtr buffer, uint32_t options,
648 uint32_t padding)
649 {
650 RESET_ERROR;
651 return xmp_serialize_and_format(xmp, buffer, options, padding, "\n", " ",
652 0);
653 }
654
655 API_EXPORT
xmp_serialize_and_format(XmpPtr xmp,XmpStringPtr buffer,uint32_t options,uint32_t padding,const char * newline,const char * tab,int32_t indent)656 bool xmp_serialize_and_format(XmpPtr xmp, XmpStringPtr buffer, uint32_t options,
657 uint32_t padding, const char *newline,
658 const char *tab, int32_t indent)
659 {
660 CHECK_PTR(xmp, false);
661 CHECK_PTR(buffer, false);
662 RESET_ERROR;
663
664 SXMPMeta *txmp = (SXMPMeta *)xmp;
665 try {
666 txmp->SerializeToBuffer(STRING(buffer), options, padding, newline, tab,
667 indent);
668 }
669 catch (const XMP_Error &e) {
670 set_error(e);
671 return false;
672 }
673 return true;
674 }
675
676 API_EXPORT
xmp_free(XmpPtr xmp)677 bool xmp_free(XmpPtr xmp)
678 {
679 CHECK_PTR(xmp, false);
680 RESET_ERROR;
681 SXMPMeta *txmp = (SXMPMeta *)xmp;
682 delete txmp;
683 return true;
684 }
685
686 API_EXPORT
xmp_get_property(XmpPtr xmp,const char * schema,const char * name,XmpStringPtr property,uint32_t * propsBits)687 bool xmp_get_property(XmpPtr xmp, const char *schema, const char *name,
688 XmpStringPtr property, uint32_t *propsBits)
689 {
690 CHECK_PTR(xmp, false);
691 RESET_ERROR;
692
693 bool ret = false;
694 try {
695 auto txmp = reinterpret_cast<const SXMPMeta *>(xmp);
696 XMP_OptionBits optionBits;
697 ret = txmp->GetProperty(schema, name, STRING(property), &optionBits);
698 if (propsBits) {
699 *propsBits = optionBits;
700 }
701 }
702 catch (const XMP_Error &e) {
703 set_error(e);
704 }
705 return ret;
706 }
707
708 API_EXPORT
xmp_get_property_date(XmpPtr xmp,const char * schema,const char * name,XmpDateTime * property,uint32_t * propsBits)709 bool xmp_get_property_date(XmpPtr xmp, const char *schema, const char *name,
710 XmpDateTime *property, uint32_t *propsBits)
711 {
712 CHECK_PTR(xmp, false);
713 RESET_ERROR;
714
715 bool ret = false;
716 try {
717 auto txmp = reinterpret_cast<const SXMPMeta *>(xmp);
718 XMP_OptionBits optionBits;
719 XMP_DateTime dt;
720 // memset((void*)&dt, 1, sizeof(XMP_DateTime));
721 ret = txmp->GetProperty_Date(schema, name, &dt, &optionBits);
722 ASSIGN((*property), dt);
723 if (propsBits) {
724 *propsBits = optionBits;
725 }
726 }
727 catch (const XMP_Error &e) {
728 set_error(e);
729 }
730 return ret;
731 }
732
733 API_EXPORT
xmp_get_property_float(XmpPtr xmp,const char * schema,const char * name,double * property,uint32_t * propsBits)734 bool xmp_get_property_float(XmpPtr xmp, const char *schema, const char *name,
735 double *property, uint32_t *propsBits)
736 {
737 CHECK_PTR(xmp, false);
738 RESET_ERROR;
739
740 bool ret = false;
741 try {
742 auto txmp = reinterpret_cast<const SXMPMeta *>(xmp);
743 XMP_OptionBits optionBits;
744 ret = txmp->GetProperty_Float(schema, name, property, &optionBits);
745 if (propsBits) {
746 *propsBits = optionBits;
747 }
748 }
749 catch (const XMP_Error &e) {
750 set_error(e);
751 }
752 return ret;
753 }
754
755 API_EXPORT
xmp_get_property_bool(XmpPtr xmp,const char * schema,const char * name,bool * property,uint32_t * propsBits)756 bool xmp_get_property_bool(XmpPtr xmp, const char *schema, const char *name,
757 bool *property, uint32_t *propsBits)
758 {
759 CHECK_PTR(xmp, false);
760 RESET_ERROR;
761
762 bool ret = false;
763 try {
764 auto txmp = reinterpret_cast<const SXMPMeta *>(xmp);
765 XMP_OptionBits optionBits;
766 ret = txmp->GetProperty_Bool(schema, name, property, &optionBits);
767 if (propsBits) {
768 *propsBits = optionBits;
769 }
770 }
771 catch (const XMP_Error &e) {
772 set_error(e);
773 }
774 return ret;
775 }
776
777 API_EXPORT
xmp_get_property_int32(XmpPtr xmp,const char * schema,const char * name,int32_t * property,uint32_t * propsBits)778 bool xmp_get_property_int32(XmpPtr xmp, const char *schema, const char *name,
779 int32_t *property, uint32_t *propsBits)
780 {
781 CHECK_PTR(xmp, false);
782 RESET_ERROR;
783
784 bool ret = false;
785 try {
786 auto txmp = reinterpret_cast<const SXMPMeta *>(xmp);
787 XMP_OptionBits optionBits;
788 // the long converstion is needed until XMPCore is fixed it use proper
789 // types.
790 ret = txmp->GetProperty_Int(schema, name, property, &optionBits);
791 if (propsBits) {
792 *propsBits = optionBits;
793 }
794 }
795 catch (const XMP_Error &e) {
796 set_error(e);
797 }
798 return ret;
799 }
800
801 API_EXPORT
xmp_get_property_int64(XmpPtr xmp,const char * schema,const char * name,int64_t * property,uint32_t * propsBits)802 bool xmp_get_property_int64(XmpPtr xmp, const char *schema, const char *name,
803 int64_t *property, uint32_t *propsBits)
804 {
805 CHECK_PTR(xmp, false);
806 RESET_ERROR;
807
808 bool ret = false;
809 try {
810 auto txmp = reinterpret_cast<const SXMPMeta *>(xmp);
811 XMP_OptionBits optionBits;
812 ret = txmp->GetProperty_Int64(schema, name, property, &optionBits);
813 if (propsBits) {
814 *propsBits = optionBits;
815 }
816 }
817 catch (const XMP_Error &e) {
818 set_error(e);
819 }
820 return ret;
821 }
822
823 API_EXPORT
xmp_get_array_item(XmpPtr xmp,const char * schema,const char * name,int32_t index,XmpStringPtr property,uint32_t * propsBits)824 bool xmp_get_array_item(XmpPtr xmp, const char *schema, const char *name,
825 int32_t index, XmpStringPtr property,
826 uint32_t *propsBits)
827 {
828 CHECK_PTR(xmp, false);
829 RESET_ERROR;
830
831 bool ret = false;
832 try {
833 auto txmp = reinterpret_cast<const SXMPMeta *>(xmp);
834 XMP_OptionBits optionBits;
835 ret = txmp->GetArrayItem(schema, name, index, STRING(property),
836 &optionBits);
837 if (propsBits) {
838 *propsBits = optionBits;
839 }
840 }
841 catch (const XMP_Error &e) {
842 set_error(e);
843 }
844 return ret;
845 }
846
847 API_EXPORT
xmp_set_property(XmpPtr xmp,const char * schema,const char * name,const char * value,uint32_t optionBits)848 bool xmp_set_property(XmpPtr xmp, const char *schema, const char *name,
849 const char *value, uint32_t optionBits)
850 {
851 CHECK_PTR(xmp, false);
852 RESET_ERROR;
853
854 bool ret = false;
855 auto txmp = reinterpret_cast<SXMPMeta *>(xmp);
856 // see bug #16030
857 // when it is a struct or an array, get prop return an empty string
858 // but it fail if passed an empty string
859 if ((optionBits & (XMP_PROP_VALUE_IS_STRUCT | XMP_PROP_VALUE_IS_ARRAY)) &&
860 (*value == 0)) {
861 value = NULL;
862 }
863 try {
864 txmp->SetProperty(schema, name, value, optionBits);
865 ret = true;
866 }
867 catch (const XMP_Error &e) {
868 set_error(e);
869 }
870 catch (...) {
871 }
872 return ret;
873 }
874
875 API_EXPORT
xmp_set_property_date(XmpPtr xmp,const char * schema,const char * name,const XmpDateTime * value,uint32_t optionBits)876 bool xmp_set_property_date(XmpPtr xmp, const char *schema, const char *name,
877 const XmpDateTime *value, uint32_t optionBits)
878 {
879 CHECK_PTR(xmp, false);
880 RESET_ERROR;
881
882 bool ret = false;
883 auto txmp = reinterpret_cast<SXMPMeta *>(xmp);
884 try {
885 XMP_DateTime dt;
886 ASSIGN(dt, (*value));
887 txmp->SetProperty_Date(schema, name, dt, optionBits);
888 ret = true;
889 }
890 catch (const XMP_Error &e) {
891 set_error(e);
892 }
893 catch (...) {
894 }
895 return ret;
896 }
897
898 API_EXPORT
xmp_set_property_float(XmpPtr xmp,const char * schema,const char * name,double value,uint32_t optionBits)899 bool xmp_set_property_float(XmpPtr xmp, const char *schema, const char *name,
900 double value, uint32_t optionBits)
901 {
902 CHECK_PTR(xmp, false);
903 RESET_ERROR;
904
905 bool ret = false;
906 auto txmp = reinterpret_cast<SXMPMeta *>(xmp);
907 try {
908 txmp->SetProperty_Float(schema, name, value, optionBits);
909 ret = true;
910 }
911 catch (const XMP_Error &e) {
912 set_error(e);
913 }
914 catch (...) {
915 }
916 return ret;
917 }
918
919 API_EXPORT
xmp_set_property_bool(XmpPtr xmp,const char * schema,const char * name,bool value,uint32_t optionBits)920 bool xmp_set_property_bool(XmpPtr xmp, const char *schema, const char *name,
921 bool value, uint32_t optionBits)
922 {
923 CHECK_PTR(xmp, false);
924 RESET_ERROR;
925
926 bool ret = false;
927 auto txmp = reinterpret_cast<SXMPMeta *>(xmp);
928 try {
929 txmp->SetProperty_Bool(schema, name, value, optionBits);
930 ret = true;
931 }
932 catch (const XMP_Error &e) {
933 set_error(e);
934 }
935 catch (...) {
936 }
937 return ret;
938 }
939
940 API_EXPORT
xmp_set_property_int32(XmpPtr xmp,const char * schema,const char * name,int32_t value,uint32_t optionBits)941 bool xmp_set_property_int32(XmpPtr xmp, const char *schema, const char *name,
942 int32_t value, uint32_t optionBits)
943 {
944 CHECK_PTR(xmp, false);
945 RESET_ERROR;
946
947 bool ret = false;
948 auto txmp = reinterpret_cast<SXMPMeta *>(xmp);
949 try {
950 txmp->SetProperty_Int(schema, name, value, optionBits);
951 ret = true;
952 }
953 catch (const XMP_Error &e) {
954 set_error(e);
955 }
956 catch (...) {
957 }
958 return ret;
959 }
960
961 API_EXPORT
xmp_set_property_int64(XmpPtr xmp,const char * schema,const char * name,int64_t value,uint32_t optionBits)962 bool xmp_set_property_int64(XmpPtr xmp, const char *schema, const char *name,
963 int64_t value, uint32_t optionBits)
964 {
965 CHECK_PTR(xmp, false);
966 RESET_ERROR;
967
968 bool ret = false;
969 auto txmp = reinterpret_cast<SXMPMeta *>(xmp);
970 try {
971 txmp->SetProperty_Int64(schema, name, value, optionBits);
972 ret = true;
973 }
974 catch (const XMP_Error &e) {
975 set_error(e);
976 }
977 catch (...) {
978 }
979 return ret;
980 }
981
982 API_EXPORT
xmp_set_array_item(XmpPtr xmp,const char * schema,const char * name,int32_t index,const char * value,uint32_t optionBits)983 bool xmp_set_array_item(XmpPtr xmp, const char *schema, const char *name,
984 int32_t index, const char *value, uint32_t optionBits)
985 {
986 CHECK_PTR(xmp, false);
987 RESET_ERROR;
988
989 bool ret = false;
990 auto txmp = reinterpret_cast<SXMPMeta *>(xmp);
991 try {
992 txmp->SetArrayItem(schema, name, index, value, optionBits);
993 ret = true;
994 }
995 catch (const XMP_Error &e) {
996 set_error(e);
997 }
998 catch (...) {
999 }
1000 return ret;
1001 }
1002
1003 API_EXPORT
xmp_append_array_item(XmpPtr xmp,const char * schema,const char * name,uint32_t arrayOptions,const char * value,uint32_t optionBits)1004 bool xmp_append_array_item(XmpPtr xmp, const char *schema, const char *name,
1005 uint32_t arrayOptions, const char *value,
1006 uint32_t optionBits)
1007 {
1008 CHECK_PTR(xmp, false);
1009 RESET_ERROR;
1010
1011 bool ret = false;
1012 auto txmp = reinterpret_cast<SXMPMeta *>(xmp);
1013 try {
1014 txmp->AppendArrayItem(schema, name, arrayOptions, value, optionBits);
1015 ret = true;
1016 }
1017 catch (const XMP_Error &e) {
1018 set_error(e);
1019 }
1020 catch (...) {
1021 }
1022 return ret;
1023 }
1024
1025 API_EXPORT
xmp_delete_property(XmpPtr xmp,const char * schema,const char * name)1026 bool xmp_delete_property(XmpPtr xmp, const char *schema, const char *name)
1027 {
1028 CHECK_PTR(xmp, false);
1029 RESET_ERROR;
1030
1031 bool ret = true;
1032 auto txmp = reinterpret_cast<SXMPMeta *>(xmp);
1033 try {
1034 txmp->DeleteProperty(schema, name);
1035 }
1036 catch (const XMP_Error &e) {
1037 set_error(e);
1038 ret = false;
1039 }
1040 catch (...) {
1041 ret = false;
1042 }
1043 return ret;
1044 }
1045
1046 API_EXPORT
xmp_has_property(XmpPtr xmp,const char * schema,const char * name)1047 bool xmp_has_property(XmpPtr xmp, const char *schema, const char *name)
1048 {
1049 CHECK_PTR(xmp, false);
1050 RESET_ERROR;
1051
1052 bool ret = true;
1053 auto txmp = reinterpret_cast<const SXMPMeta *>(xmp);
1054 try {
1055 ret = txmp->DoesPropertyExist(schema, name);
1056 }
1057 catch (const XMP_Error &e) {
1058 set_error(e);
1059 ret = false;
1060 }
1061 catch (...) {
1062 ret = false;
1063 }
1064 return ret;
1065 }
1066
1067 API_EXPORT
xmp_get_localized_text(XmpPtr xmp,const char * schema,const char * name,const char * genericLang,const char * specificLang,XmpStringPtr actualLang,XmpStringPtr itemValue,uint32_t * propsBits)1068 bool xmp_get_localized_text(XmpPtr xmp, const char *schema, const char *name,
1069 const char *genericLang, const char *specificLang,
1070 XmpStringPtr actualLang, XmpStringPtr itemValue,
1071 uint32_t *propsBits)
1072 {
1073 CHECK_PTR(xmp, false);
1074 RESET_ERROR;
1075
1076 bool ret = false;
1077 try {
1078 auto txmp = reinterpret_cast<const SXMPMeta *>(xmp);
1079 XMP_OptionBits optionBits;
1080 ret = txmp->GetLocalizedText(schema, name, genericLang, specificLang,
1081 STRING(actualLang), STRING(itemValue),
1082 &optionBits);
1083 if (propsBits) {
1084 *propsBits = optionBits;
1085 }
1086 }
1087 catch (const XMP_Error &e) {
1088 set_error(e);
1089 ret = false;
1090 }
1091 return ret;
1092 }
1093
1094 API_EXPORT
xmp_set_localized_text(XmpPtr xmp,const char * schema,const char * name,const char * genericLang,const char * specificLang,const char * value,uint32_t optionBits)1095 bool xmp_set_localized_text(XmpPtr xmp, const char *schema, const char *name,
1096 const char *genericLang, const char *specificLang,
1097 const char *value, uint32_t optionBits)
1098 {
1099 CHECK_PTR(xmp, false);
1100 RESET_ERROR;
1101
1102 bool ret = true;
1103 auto txmp = reinterpret_cast<SXMPMeta *>(xmp);
1104 try {
1105 txmp->SetLocalizedText(schema, name, genericLang, specificLang, value,
1106 optionBits);
1107 }
1108 catch (const XMP_Error &e) {
1109 set_error(e);
1110 ret = false;
1111 }
1112 catch (...) {
1113 ret = false;
1114 }
1115 return ret;
1116 }
1117
1118 API_EXPORT
xmp_delete_localized_text(XmpPtr xmp,const char * schema,const char * name,const char * genericLang,const char * specificLang)1119 bool xmp_delete_localized_text(XmpPtr xmp, const char *schema, const char *name,
1120 const char *genericLang,
1121 const char *specificLang)
1122 {
1123 CHECK_PTR(xmp, false);
1124 RESET_ERROR;
1125
1126 bool ret = true;
1127 auto txmp = reinterpret_cast<SXMPMeta *>(xmp);
1128 try {
1129 txmp->DeleteLocalizedText(schema, name, genericLang, specificLang);
1130 }
1131 catch (const XMP_Error &e) {
1132 set_error(e);
1133 ret = false;
1134 }
1135 catch (...) {
1136 ret = false;
1137 }
1138 return ret;
1139 }
1140
1141 API_EXPORT
xmp_string_new()1142 XmpStringPtr xmp_string_new()
1143 {
1144 return (XmpStringPtr) new std::string;
1145 }
1146
1147 API_EXPORT
xmp_string_free(XmpStringPtr s)1148 void xmp_string_free(XmpStringPtr s)
1149 {
1150 auto str = reinterpret_cast<std::string *>(s);
1151 delete str;
1152 }
1153
1154 API_EXPORT
xmp_string_cstr(XmpStringPtr s)1155 const char *xmp_string_cstr(XmpStringPtr s)
1156 {
1157 CHECK_PTR(s, NULL);
1158 return reinterpret_cast<const std::string *>(s)->c_str();
1159 }
1160
1161 API_EXPORT
xmp_string_len(XmpStringPtr s)1162 size_t xmp_string_len(XmpStringPtr s)
1163 {
1164 CHECK_PTR(s, 0);
1165 return reinterpret_cast<const std::string *>(s)->size();
1166 }
1167
1168 API_EXPORT
xmp_iterator_new(XmpPtr xmp,const char * schema,const char * propName,XmpIterOptions options)1169 XmpIteratorPtr xmp_iterator_new(XmpPtr xmp, const char *schema,
1170 const char *propName, XmpIterOptions options)
1171 {
1172 CHECK_PTR(xmp, NULL);
1173 RESET_ERROR;
1174
1175 try {
1176 auto xiter = std::unique_ptr<SXMPIterator>(
1177 new SXMPIterator(*(SXMPMeta *)xmp, schema, propName, options));
1178
1179 return reinterpret_cast<XmpIteratorPtr>(xiter.release());
1180 }
1181 catch (const XMP_Error &e) {
1182 set_error(e);
1183 }
1184
1185 return NULL;
1186 }
1187
1188 API_EXPORT
xmp_iterator_free(XmpIteratorPtr iter)1189 bool xmp_iterator_free(XmpIteratorPtr iter)
1190 {
1191 CHECK_PTR(iter, false);
1192 RESET_ERROR;
1193 auto titer = reinterpret_cast<SXMPIterator *>(iter);
1194 delete titer;
1195 return true;
1196 }
1197
1198 API_EXPORT
xmp_iterator_next(XmpIteratorPtr iter,XmpStringPtr schema,XmpStringPtr propName,XmpStringPtr propValue,uint32_t * options)1199 bool xmp_iterator_next(XmpIteratorPtr iter, XmpStringPtr schema,
1200 XmpStringPtr propName, XmpStringPtr propValue,
1201 uint32_t *options)
1202 {
1203 CHECK_PTR(iter, false);
1204 RESET_ERROR;
1205 auto titer = reinterpret_cast<SXMPIterator *>(iter);
1206 return titer->Next(reinterpret_cast<std::string *>(schema),
1207 reinterpret_cast<std::string *>(propName),
1208 reinterpret_cast<std::string *>(propValue), options);
1209 }
1210
1211 API_EXPORT
xmp_iterator_skip(XmpIteratorPtr iter,XmpIterSkipOptions options)1212 bool xmp_iterator_skip(XmpIteratorPtr iter, XmpIterSkipOptions options)
1213 {
1214 CHECK_PTR(iter, false);
1215 RESET_ERROR;
1216 auto titer = reinterpret_cast<SXMPIterator *>(iter);
1217 titer->Skip(options);
1218 return true;
1219 }
1220
1221 API_EXPORT
xmp_datetime_compare(XmpDateTime * left,XmpDateTime * right)1222 int xmp_datetime_compare(XmpDateTime *left, XmpDateTime *right)
1223 {
1224 if (!left && !right) {
1225 return 0;
1226 }
1227 if (!left) {
1228 return -1;
1229 }
1230 if (!right) {
1231 return 1;
1232 }
1233 XMP_DateTime _left;
1234 ASSIGN(_left, *left);
1235 XMP_DateTime _right;
1236 ASSIGN(_right, *right);
1237 return XMPUtils::CompareDateTime(_left, _right);
1238 }
1239
1240 #ifdef __cplusplus
1241 }
1242 #endif
1243