Add XMP Initialisation/Cleanup code to every main()
Fix #976. Add XMP Initialisation/Cleanup code to all main() programs
This commit is contained in:
commit
0fd1ad3ed0
37
README.md
37
README.md
@ -20,6 +20,8 @@
|
||||
11. [Debugging Exiv2](#2-11)
|
||||
12. [Building Exiv2 with Clang and other build chains](#2-12)
|
||||
13. [Building Exiv2 with ccache](#2-13)
|
||||
14. [Thread Safety](#2-14)
|
||||
15. [Library Initialisation and Cleanup](#2-15)
|
||||
3. [License and Support](#3)
|
||||
1. [License](#3-1)
|
||||
2. [Support](#3-2)
|
||||
@ -553,6 +555,39 @@ $ make
|
||||
Due to the way in which ccache is installed in Fedora (and other Linux distros), ccache effectively replaces the compiler. A default build or **-DBUILD\_WITH\_CCACHE=Off** is not effective and the environment variable CCACHE_DISABLE is required to disable ccache. [https://github.com/Exiv2/exiv2/issues/361](https://github.com/Exiv2/exiv2/issues/361)
|
||||
|
||||
[TOC](#TOC)
|
||||
|
||||
<div id="2-14">
|
||||
|
||||
### 2.14 Thread Safety
|
||||
|
||||
Exiv2 heavily relies on standard C++ containers. Static or global variables are used read-only, with the exception of the XMP namespace registration function (see below). Thus Exiv2 is thread safe in the same sense as C++ containers:
|
||||
Different instances of the same class can safely be used concurrently in multiple threads.
|
||||
|
||||
In order to use the same instance of a class concurrently in multiple threads the application must serialize all write access to the object.
|
||||
|
||||
The level of thread safety within Exiv2 varies depending on the type of metadata: The Exif and IPTC code is reentrant. The XMP code uses the Adobe XMP toolkit (XMP SDK), which according to its documentation is thread-safe. It actually uses mutexes to serialize critical sections. However, the XMP SDK initialisation function is not mutex protected, thus Exiv2::XmpParser::initialize is not thread-safe. In addition, Exiv2::XmpProperties::registerNs writes to a static class variable, and is also not thread-safe.
|
||||
|
||||
Therefore, multi-threaded applications need to ensure that these two XMP functions are serialized, e.g., by calling them from an initialization section which is run before any threads are started.
|
||||
|
||||
[TOC](#TOC)
|
||||
|
||||
<div id="2-15">
|
||||
|
||||
### 2.15 Library Initialisation and Cleanup
|
||||
|
||||
As discussed in the section on Thread Safety, Exiv2 classes for Exif and IPTC metadata are fully reentrant and require no initialisation or cleanup.
|
||||
|
||||
Adobe's XMPsdk is generally thread-safe, however it has to be initialized and terminated before and after starting any threads to access XMP metadata. The Exiv2 library will initialize this if necessary, however it does not terminate the XMPsdk.
|
||||
|
||||
The Exiv2 command-line and the sample applications call the following at the outset:
|
||||
|
||||
```
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
```
|
||||
|
||||
[TOC](#TOC)
|
||||
|
||||
<div id="3">
|
||||
|
||||
## 3 License and Support
|
||||
@ -895,4 +930,4 @@ Work in progress: [https://github.com/Exiv2/exiv2/issues/902](https://github.co
|
||||
|
||||
Robin Mills
|
||||
|
||||
Revised: 2019-07-29
|
||||
Revised: 2019-08-03
|
||||
|
||||
@ -114,6 +114,9 @@ void sftpcon(const std::string& url) {
|
||||
|
||||
int main(int argc,const char** argv)
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if (argc < 2) {
|
||||
std::cout << "Usage: " << argv[0] << " url {-http1_0}" << std::endl;
|
||||
return 1;
|
||||
|
||||
@ -10,6 +10,9 @@
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file\n";
|
||||
return 1;
|
||||
|
||||
@ -43,6 +43,9 @@ static const EasyAccess easyAccess[] = {
|
||||
|
||||
int main(int argc, char **argv)
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file\n";
|
||||
return 1;
|
||||
|
||||
@ -19,6 +19,8 @@
|
||||
// Main
|
||||
int main(int argc, char* const argv[])
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file\n";
|
||||
|
||||
@ -24,6 +24,9 @@ void print(const std::string& file);
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file\n";
|
||||
return 1;
|
||||
|
||||
@ -152,6 +152,9 @@ std::string formatXML(Exiv2::ExifData& exifData)
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
int main(int argc,const char* argv[])
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
format_t formats;
|
||||
formats["wolf"] = wolf;
|
||||
formats["csv" ] = csv ;
|
||||
|
||||
@ -29,6 +29,9 @@
|
||||
|
||||
int _tmain(int argc, _tchar* const argv[])
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
const _tchar* prog = argv[0];
|
||||
const _tchar* file = argv[1];
|
||||
|
||||
|
||||
@ -11,6 +11,9 @@
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if (argc != 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " file key\n";
|
||||
return 1;
|
||||
|
||||
@ -268,6 +268,9 @@ void fileSystemPush(const char* path,Jzon::Node& nfs)
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
try {
|
||||
if (argc < 2 || argc > 3) {
|
||||
std::cout << "Usage: " << argv[0] << " [-option] file" << std::endl;
|
||||
|
||||
@ -764,6 +764,9 @@ bool mySort(const std::string& a, const std::string& b)
|
||||
|
||||
int main(int argc,const char* argv[])
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
int result=0;
|
||||
const char* program = argv[0];
|
||||
|
||||
|
||||
@ -83,6 +83,9 @@ public:
|
||||
|
||||
int main(int argc, char** const argv)
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
int n;
|
||||
|
||||
#ifdef EXV_HAVE_UNISTD_H
|
||||
|
||||
@ -20,6 +20,9 @@ static int testSyntax(const char* arg)
|
||||
|
||||
int main(int argc,const char** argv)
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if ( argc < 2 ) {
|
||||
std::cout << "usage : " << argv[0] << " [key value]+" << std::endl;
|
||||
std::cout << "example: " << argv[0] << " [[-url] url | -server clanmills.com -page /LargsPanorama.jpg] -header \"Range: bytes=0-200\"" << std::endl;
|
||||
|
||||
@ -9,14 +9,15 @@ Config loaded from : 'initest.ini' version=6, name=Bob Smith, email=bob@smith.co
|
||||
|
||||
// Example that shows simple usage of the INIReader class
|
||||
|
||||
#include <iostream>
|
||||
#include <exiv2/exiv2.hpp>
|
||||
|
||||
// #include <exiv2/exiv2.h>
|
||||
#include "config.h"
|
||||
#include "ini.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int main()
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
int result = 0 ;
|
||||
const char* ini = "ini-test.ini";
|
||||
Exiv2::INIReader reader(ini);
|
||||
|
||||
@ -46,7 +46,10 @@ int WriteReadSeek(BasicIo &io);
|
||||
// Main
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
try {
|
||||
if (argc != 4) {
|
||||
std::cout << "Usage: " << argv[0] << " filein fileout1 fileout2\n";
|
||||
std::cout << "fileouts are overwritten and should match filein exactly\n";
|
||||
|
||||
@ -10,6 +10,9 @@
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file\n";
|
||||
return 1;
|
||||
|
||||
@ -11,6 +11,9 @@
|
||||
int main(int argc, char* const argv[])
|
||||
try {
|
||||
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file\n";
|
||||
return 1;
|
||||
|
||||
@ -26,6 +26,9 @@ void processModify(const std::string& line, int num, IptcData &iptcData);
|
||||
// Main
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
try {
|
||||
|
||||
if (argc != 2) {
|
||||
|
||||
@ -19,6 +19,9 @@ using namespace Exiv2;
|
||||
|
||||
int main()
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
int tc = 0;
|
||||
int rc = 0;
|
||||
|
||||
|
||||
@ -8,6 +8,9 @@
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if (argc != 3) {
|
||||
std::cout << "Usage: " << argv[0] << " image datafile\n";
|
||||
return 1;
|
||||
|
||||
@ -40,6 +40,9 @@
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
// Handle command line arguments
|
||||
Params params;
|
||||
if (params.getopt(argc, argv)) {
|
||||
|
||||
@ -11,6 +11,9 @@ using namespace Exiv2;
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file\n";
|
||||
return 1;
|
||||
|
||||
@ -11,6 +11,9 @@
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
try {
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file\n";
|
||||
|
||||
@ -62,6 +62,9 @@ void reportExifMetadataCount(int n,const char* argv[])
|
||||
|
||||
int main(int argc,const char* argv[])
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
int result = 0;
|
||||
|
||||
if ( argc < 2 ) {
|
||||
|
||||
@ -12,6 +12,9 @@
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file\n";
|
||||
return 1;
|
||||
|
||||
@ -10,6 +10,9 @@
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file\n";
|
||||
return 1;
|
||||
|
||||
@ -12,6 +12,9 @@
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if (argc < 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file {--nocurl | --curl}\n\n";
|
||||
return 1;
|
||||
|
||||
@ -40,6 +40,9 @@ const char* testcases[] = {
|
||||
|
||||
int main()
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
std::cout << std::setfill(' ');
|
||||
|
||||
std::cout << std::setw(12) << std::left << "string";
|
||||
|
||||
@ -18,6 +18,9 @@ using namespace Exiv2;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
int rc = EXIT_SUCCESS;
|
||||
std::ostringstream out;
|
||||
try {
|
||||
|
||||
@ -19,6 +19,9 @@ void mini9(const char* path);
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file\n";
|
||||
return 1;
|
||||
|
||||
@ -64,6 +64,9 @@ std::string tiffTagName(uint32_t tag)
|
||||
// Main program
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if (argc != 3) {
|
||||
std::cout << "Usage: " << argv[0] << " tag group\n"
|
||||
<< "Print the TIFF path for a tag and group (decimal numbers)\n";
|
||||
|
||||
@ -45,7 +45,10 @@ static size_t exifMetadataCount(Exiv2::Image::AutoPtr& image)
|
||||
// Main
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
try {
|
||||
// Handle command line arguments
|
||||
Params params(":iecCahsx");
|
||||
if (params.getopt(argc, argv)) return params.usage();
|
||||
|
||||
@ -8,6 +8,9 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
try {
|
||||
throw Exiv2::Error(Exiv2::kerGeneralError, "ARG1", "ARG2", "ARG3");
|
||||
}
|
||||
|
||||
@ -39,7 +39,10 @@ void exifPrint(const ExifData& exifData);
|
||||
// Main
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
try {
|
||||
|
||||
if (argc != 3) {
|
||||
std::cout << "Usage: write-test file case\n\n"
|
||||
|
||||
@ -23,7 +23,10 @@ void print(const std::string& file);
|
||||
// Main
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
try {
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file\n";
|
||||
return 1;
|
||||
|
||||
@ -11,6 +11,9 @@
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
try {
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file\n";
|
||||
|
||||
@ -10,6 +10,9 @@
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file\n";
|
||||
return 1;
|
||||
|
||||
@ -10,6 +10,9 @@
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file\n";
|
||||
return 1;
|
||||
|
||||
@ -16,7 +16,10 @@
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
try
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
try
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
|
||||
@ -19,6 +19,9 @@ bool isEqual(float a, float b)
|
||||
|
||||
int main()
|
||||
try {
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
// The XMP property container
|
||||
Exiv2::XmpData xmpData;
|
||||
|
||||
|
||||
@ -127,6 +127,9 @@ namespace {
|
||||
// Main
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
Exiv2::XmpParser::initialize();
|
||||
::atexit(Exiv2::XmpParser::terminate);
|
||||
|
||||
#ifdef EXV_ENABLE_NLS
|
||||
setlocale(LC_ALL, "");
|
||||
const std::string localeDir = Exiv2::getProcessPath() + EXV_LOCALEDIR;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user