1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
// SPDX-License-Identifier: GPL-2.0-or-later
#include <exiv2/exiv2.hpp>
#include <iostream>
using namespace Exiv2;
bool processLine(const std::string& line, int num, IptcData& iptcData);
void processAdd(const std::string& line, int num, IptcData& iptcData);
void processRemove(const std::string& line, int num, IptcData& iptcData);
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) {
std::cout << "Usage: " << argv[0] << " image\n";
std::cout << "Commands read from stdin.\n";
return EXIT_FAILURE;
}
auto image = ImageFactory::open(argv[1]);
image->readMetadata();
// Process commands
std::string line;
int num = 0;
std::getline(std::cin, line);
while (line.length() && processLine(line, ++num, image->iptcData())) {
std::getline(std::cin, line);
}
// Save any changes
image->writeMetadata();
return EXIT_SUCCESS;
} catch (Error& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return EXIT_FAILURE;
}
}
bool processLine(const std::string& line, int num, IptcData& iptcData) {
switch (line.at(0)) {
case 'a':
case 'A':
processAdd(line, num, iptcData);
break;
case 'r':
case 'R':
processRemove(line, num, iptcData);
break;
case 'm':
case 'M':
processModify(line, num, iptcData);
break;
case 'q':
case 'Q':
return false;
default:
std::ostringstream os;
os << "Unknown command (" << line.at(0) << ") at line " << num;
throw Error(ErrorCode::kerErrorMessage, os.str());
}
return true;
}
void processAdd(const std::string& line, int num, IptcData& iptcData) {
std::string::size_type keyStart = line.find_first_not_of(" \t", 1);
std::string::size_type keyEnd = line.find_first_of(" \t", keyStart + 1);
std::string::size_type dataStart = line.find_first_not_of(" \t", keyEnd + 1);
if (keyStart == std::string::npos || keyEnd == std::string::npos || dataStart == std::string::npos) {
std::ostringstream os;
os << "Invalid \'a\' command at line " << num;
throw Error(ErrorCode::kerErrorMessage, os.str());
}
std::string key(line.substr(keyStart, keyEnd - keyStart));
IptcKey iptcKey(key);
std::string data(line.substr(dataStart));
// if data starts and ends with quotes, remove them
if (data.at(0) == '\"' && data.at(data.size() - 1) == '\"') {
data = data.substr(1, data.size() - 2);
}
TypeId type = IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record());
Value::UniquePtr value = Value::create(type);
value->read(data);
int rc = iptcData.add(iptcKey, value.get());
if (rc) {
throw Error(ErrorCode::kerErrorMessage, "Iptc dataset already exists and is not repeatable");
}
}
void processRemove(const std::string& line, int num, IptcData& iptcData) {
std::string::size_type keyStart = line.find_first_not_of(" \t", 1);
if (keyStart == std::string::npos) {
std::ostringstream os;
os << "Invalid \'r\' command at line " << num;
throw Error(ErrorCode::kerErrorMessage, os.str());
}
const std::string key(line.substr(keyStart));
IptcKey iptcKey(key);
auto iter = iptcData.findKey(iptcKey);
if (iter != iptcData.end()) {
iptcData.erase(iter);
}
}
void processModify(const std::string& line, int num, IptcData& iptcData) {
std::string::size_type keyStart = line.find_first_not_of(" \t", 1);
std::string::size_type keyEnd = line.find_first_of(" \t", keyStart + 1);
std::string::size_type dataStart = line.find_first_not_of(" \t", keyEnd + 1);
if (keyStart == std::string::npos || keyEnd == std::string::npos || dataStart == std::string::npos) {
std::ostringstream os;
os << "Invalid \'m\' command at line " << num;
throw Error(ErrorCode::kerErrorMessage, os.str());
}
std::string key(line.substr(keyStart, keyEnd - keyStart));
IptcKey iptcKey(key);
std::string data(line.substr(dataStart));
// if data starts and ends with quotes, remove them
if (data.at(0) == '\"' && data.at(data.size() - 1) == '\"') {
data = data.substr(1, data.size() - 2);
}
TypeId type = IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record());
Value::UniquePtr value = Value::create(type);
value->read(data);
auto iter = iptcData.findKey(iptcKey);
if (iter != iptcData.end()) {
iter->setValue(value.get());
} else {
int rc = iptcData.add(iptcKey, value.get());
if (rc) {
throw Error(ErrorCode::kerErrorMessage, "Iptc dataset already exists and is not repeatable");
}
}
}
|