Add XMP Initialisation/Cleanup code to every main()

Fix #976. Add XMP Initialisation/Cleanup code to all main() programs
This commit is contained in:
D4N 2019-10-05 17:11:57 +02:00 committed by GitHub
commit 0fd1ad3ed0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 162 additions and 10 deletions

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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";

View File

@ -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;

View File

@ -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 ;

View File

@ -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];

View File

@ -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;

View File

@ -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;

View File

@ -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];

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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";

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -19,6 +19,9 @@ using namespace Exiv2;
int main()
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
int tc = 0;
int rc = 0;

View File

@ -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;

View File

@ -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)) {

View File

@ -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;

View File

@ -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";

View File

@ -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 ) {

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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";

View File

@ -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 {

View File

@ -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;

View File

@ -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";

View File

@ -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();

View File

@ -8,6 +8,9 @@
int main()
{
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
try {
throw Exiv2::Error(Exiv2::kerGeneralError, "ARG1", "ARG2", "ARG3");
}

View File

@ -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"

View File

@ -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;

View File

@ -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";

View File

@ -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;

View File

@ -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;

View File

@ -16,7 +16,10 @@
int main(int argc, char** argv)
{
try
Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate);
try
{
if (argc != 2)
{

View File

@ -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;

View File

@ -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;