From 5b36ac5babfa090d2452f60ffa1cbb85f516e5a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20D=C3=ADaz=20M=C3=A1s?= Date: Thu, 31 Mar 2022 21:52:52 +0200 Subject: [PATCH] Remove exiv2json sample and tests depending on it --- samples/CMakeLists.txt | 5 +- samples/Jzon.cpp | 974 ---------------------------- samples/Jzon.h | 517 --------------- samples/exiv2json.cpp | 330 ---------- tests/bash_tests/test_issue_1054.py | 280 -------- tests/bash_tests/test_issue_984.py | 20 - 6 files changed, 1 insertion(+), 2125 deletions(-) delete mode 100644 samples/Jzon.cpp delete mode 100644 samples/Jzon.h delete mode 100644 samples/exiv2json.cpp delete mode 100644 tests/bash_tests/test_issue_1054.py delete mode 100644 tests/bash_tests/test_issue_984.py diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 70036b6339..41b3abbc47 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -70,10 +70,7 @@ target_include_directories(path-test PRIVATE ${CMAKE_SOURCE_DIR}/app ) # To find getopt.hpp -add_executable( exiv2json exiv2json.cpp Jzon.cpp Jzon.h) -list(APPEND APPLICATIONS exiv2json) - -install( TARGETS metacopy exiv2json RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +install( TARGETS metacopy RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) if( EXPAT_FOUND ) add_executable( geotag geotag.cpp) diff --git a/samples/Jzon.cpp b/samples/Jzon.cpp deleted file mode 100644 index eabb0c596e..0000000000 --- a/samples/Jzon.cpp +++ /dev/null @@ -1,974 +0,0 @@ -// ***************************************************************** -*- C++ -*- -/* -Copyright (c) 2013 Johannes Häggqvist - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#ifdef _WINDLL -#define JzonAPI __declspec(dllexport) -#endif - -#ifdef _MSC_VER -#define _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS -#endif - -#include "Jzon.h" - -#include -#include -#include -#include -#include - -namespace Jzon { -class FormatInterpreter { - public: - FormatInterpreter() { - SetFormat(NoFormat); - } - explicit FormatInterpreter(const Format& format) { - SetFormat(format); - } - - void SetFormat(const Format& format) { - this->format = format; - indentationChar = (format.useTabs ? '\t' : ' '); - spacing = (format.spacing ? " " : ""); - newline = (format.newline ? "\n" : spacing); - } - - std::string GetIndentation(size_t level) const { - if (format.newline) - return std::string(format.indentSize * level, indentationChar); - return ""; - } - - inline const std::string& GetNewline() const { - return newline; - } - inline const std::string& GetSpacing() const { - return spacing; - } - - private: - Format format; - char indentationChar; - std::string newline; - std::string spacing; -}; - -inline bool IsWhitespace(char c) { - return (c == '\n' || c == ' ' || c == '\t' || c == '\r' || c == '\f'); -} -inline bool IsNumber(char c) { - return ((c >= '0' && c <= '9') || c == '.' || c == '-'); -} - -Object& Node::AsObject() { - if (IsObject()) - return dynamic_cast(*this); - throw TypeException(); -} -const Object& Node::AsObject() const { - if (IsObject()) - return dynamic_cast(*this); - throw TypeException(); -} -Array& Node::AsArray() { - if (IsArray()) - return dynamic_cast(*this); - throw TypeException(); -} -const Array& Node::AsArray() const { - if (IsArray()) - return dynamic_cast(*this); - throw TypeException(); -} -Value& Node::AsValue() { - if (IsValue()) - return dynamic_cast(*this); - throw TypeException(); -} -const Value& Node::AsValue() const { - if (IsValue()) - return dynamic_cast(*this); - throw TypeException(); -} - -Node::Type Node::DetermineType(const std::string& json) { - auto jsonIt = std::find_if(json.begin(), json.end(), IsWhitespace); - if (jsonIt == json.end()) - return T_VALUE; - - switch (*jsonIt) { - case '{': - return T_OBJECT; - case '[': - return T_ARRAY; - default: - return T_VALUE; - } -} - -Value::Value() { - SetNull(); -} -Value::Value(const Value& rhs) { - Set(rhs); -} -Value::Value(const Node& rhs) { - const Value& value = rhs.AsValue(); - Set(value); -} -Value::Value(ValueType type, const std::string& value) { - Set(type, value); -} -Value::Value(const std::string& value) { - Set(value); -} -Value::Value(const char* value) { - Set(value); -} -Value::Value(const int value) { - Set(value); -} -Value::Value(const float value) { - Set(value); -} -Value::Value(const double value) { - Set(value); -} -Value::Value(const bool value) { - Set(value); -} -Node::Type Value::GetType() const { - return T_VALUE; -} -Value::ValueType Value::GetValueType() const { - return type; -} - -std::string Value::ToString() const { - if (IsNull()) { - return "null"; - } - return valueStr; -} -int Value::ToInt() const { - if (IsNumber()) { - std::stringstream sstr(valueStr); - int val = 0; - sstr >> val; - return val; - } - return 0; -} -float Value::ToFloat() const { - if (IsNumber()) { - std::stringstream sstr(valueStr); - float val = 0; - sstr >> val; - return val; - } - return 0.F; -} -double Value::ToDouble() const { - if (IsNumber()) { - std::stringstream sstr(valueStr); - double val = 0; - sstr >> val; - return val; - } - return 0.0; -} -bool Value::ToBool() const { - if (IsBool()) { - return (valueStr == "true"); - } - return false; -} - -void Value::SetNull() { - valueStr = ""; - type = VT_NULL; -} -void Value::Set(const Value& value) { - if (this != &value) { - valueStr = value.valueStr; - type = value.type; - } -} -void Value::Set(ValueType type, const std::string& value) { - valueStr = value; - this->type = type; -} -void Value::Set(const std::string& value) { - valueStr = UnescapeString(value); - type = VT_STRING; -} -void Value::Set(const char* value) { - valueStr = UnescapeString(std::string(value)); - type = VT_STRING; -} -void Value::Set(const int value) { - std::stringstream sstr; - sstr << value; - valueStr = sstr.str(); - type = VT_NUMBER; -} -void Value::Set(const float value) { - std::stringstream sstr; - sstr << value; - valueStr = sstr.str(); - type = VT_NUMBER; -} -void Value::Set(const double value) { - std::stringstream sstr; - sstr << value; - valueStr = sstr.str(); - type = VT_NUMBER; -} -void Value::Set(const bool value) { - valueStr = value ? "true" : "false"; - type = VT_BOOL; -} - -Value& Value::operator=(const Value& rhs) { - if (this != &rhs) - Set(rhs); - return *this; -} -Value& Value::operator=(const Node& rhs) { - if (this != &rhs) - Set(rhs.AsValue()); - return *this; -} -Value& Value::operator=(const std::string& rhs) { - Set(rhs); - return *this; -} -Value& Value::operator=(const char* rhs) { - Set(rhs); - return *this; -} -Value& Value::operator=(const int rhs) { - Set(rhs); - return *this; -} -Value& Value::operator=(const float rhs) { - Set(rhs); - return *this; -} -Value& Value::operator=(const double rhs) { - Set(rhs); - return *this; -} -Value& Value::operator=(const bool rhs) { - Set(rhs); - return *this; -} - -bool Value::operator==(const Value& other) const { - return ((type == other.type) && (valueStr == other.valueStr)); -} -bool Value::operator!=(const Value& other) const { - return !(*this == other); -} - -Node* Value::GetCopy() const { - return new Value(*this); -} - -// This is not the most beautiful place for these, but it'll do -using chrPair = struct { - char first; - const char* second; -}; -static constexpr std::array chars{ - chrPair{'\\', "\\\\"}, chrPair{'/', "\\/"}, chrPair{'\"', "\\\""}, chrPair{'\n', "\\n"}, - chrPair{'\t', "\\t"}, chrPair{'\b', "\\b"}, chrPair{'\f', "\\f"}, chrPair{'\r', "\\r"}, -}; -static constexpr char nullUnescaped = '\0'; -static constexpr const char* nullEscaped = "\0\0"; -const char* const& getEscaped(const char& c) { - for (auto&& chr : chars) { - if (chr.first == c) { - return chr.second; - } - } - return nullEscaped; -} -const char& getUnescaped(const char& c1, const char& c2) { - for (auto&& chr : chars) { - if (c1 == chars[0].first && c2 == chars[1].first) { - return chr.first; - } - } - return nullUnescaped; -} - -std::string Value::EscapeString(const std::string& value) { - std::string escaped; - - for (auto&& c : value) { - auto&& a = getEscaped(c); - if (a[0] != '\0') { - escaped += a[0]; - escaped += a[1]; - } else { - escaped += c; - } - } - - return escaped; -} -std::string Value::UnescapeString(const std::string& value) { - std::string unescaped; - - for (auto it = value.cbegin(); it != value.cend(); ++it) { - const char& c = (*it); - char c2 = '\0'; - if (it + 1 != value.end()) - c2 = *(it + 1); - - const char& a = getUnescaped(c, c2); - if (a != '\0') { - unescaped += a; - if (it + 1 != value.end()) - ++it; - } else { - unescaped += c; - } - } - - return unescaped; -} - -Object::Object(const Object& other) { - std::transform(other.children.begin(), other.children.end(), std::back_inserter(children), - [](const NamedNodePtr& child) { return NamedNodePtr(child.first, child.second->GetCopy()); }); -} -Object::Object(const Node& other) { - std::transform(other.AsObject().children.begin(), other.AsObject().children.end(), std::back_inserter(children), - [](const NamedNodePtr& child) { return NamedNodePtr(child.first, child.second->GetCopy()); }); -} -Object::~Object() { - Clear(); -} - -Node::Type Object::GetType() const { - return T_OBJECT; -} - -void Object::Add(const std::string& name, Node& node) { - children.emplace_back(name, node.GetCopy()); -} -void Object::Add(const std::string& name, const Value& node) { - children.emplace_back(name, new Value(node)); -} -void Object::Remove(const std::string& name) { - for (auto it = children.cbegin(); it != children.cend(); ++it) { - if ((*it).first == name) { - delete (*it).second; - children.erase(it); - break; - } - } -} - -void Object::Clear() { - for (auto&& child : children) { - delete child.second; - child.second = nullptr; - } - children.clear(); -} - -Object::iterator Object::begin() { - if (!children.empty()) - return {&children.front()}; - return {nullptr}; -} - -Object::const_iterator Object::begin() const { - if (!children.empty()) - return {&children.front()}; - return {nullptr}; -} - -Object::iterator Object::end() { - if (!children.empty()) - return {&children.back() + 1}; - return {nullptr}; -} -Object::const_iterator Object::end() const { - if (!children.empty()) - return {&children.back() + 1}; - return {nullptr}; -} - -bool Object::Has(const std::string& name) const { - return std::any_of(children.begin(), children.end(), [&](const NamedNodePtr& child) { return child.first == name; }); -} -size_t Object::GetCount() const { - return children.size(); -} -Node& Object::Get(const std::string& name) const { - for (auto&& child : children) { - if (child.first == name) { - return *child.second; - } - } - - throw NotFoundException(); -} - -Node* Object::GetCopy() const { - return new Object(*this); -} - -Array::Array(const Array& other) { - for (auto&& value : other.children) { - children.push_back(value->GetCopy()); - } -} - -Array::Array(const Node& other) { - const Array& array = other.AsArray(); - - for (auto&& value : array.children) { - children.push_back(value->GetCopy()); - } -} - -Array::~Array() { - Clear(); -} - -Node::Type Array::GetType() const { - return T_ARRAY; -} - -void Array::Add(Node& node) { - children.push_back(node.GetCopy()); -} -void Array::Add(const Value& node) { - children.push_back(new Value(node)); -} -void Array::Remove(size_t index) { - if (index < children.size()) { - auto it = children.begin() + index; - delete (*it); - children.erase(it); - } -} -void Array::Clear() { - for (auto&& child : children) { - delete child; - child = nullptr; - } - children.clear(); -} - -Array::iterator Array::begin() { - if (!children.empty()) - return {&children.front()}; - return {nullptr}; -} -Array::const_iterator Array::begin() const { - if (!children.empty()) - return {&children.front()}; - return {nullptr}; -} -Array::iterator Array::end() { - if (!children.empty()) - return {&children.back() + 1}; - return {nullptr}; -} -Array::const_iterator Array::end() const { - if (!children.empty()) - return {&children.back() + 1}; - return {nullptr}; -} - -size_t Array::GetCount() const { - return children.size(); -} -Node& Array::Get(size_t index) const { - if (index < children.size()) { - return *children.at(index); - } - - throw NotFoundException(); -} - -Node* Array::GetCopy() const { - return new Array(*this); -} - -FileWriter::FileWriter(std::string filename) : filename(std::move(filename)) { -} - -void FileWriter::WriteFile(const std::string& filename, const Node& root, const Format& format) { - FileWriter writer(filename); - writer.Write(root, format); -} - -void FileWriter::Write(const Node& root, const Format& format) { - Writer writer(root, format); - writer.Write(); - - std::fstream file(filename.c_str(), std::ios::out | std::ios::trunc); - file << writer.GetResult(); - file.close(); -} - -FileReader::FileReader(const std::string& filename) { - if (!loadFile(filename, json)) { - error = "Failed to load file"; - } -} - -bool FileReader::ReadFile(const std::string& filename, Node& node) { - FileReader reader(filename); - return reader.Read(node); -} - -bool FileReader::Read(Node& node) { - if (!error.empty()) - return false; - - Parser parser(node, json); - if (!parser.Parse()) { - error = parser.GetError(); - return false; - } - return true; -} - -Node::Type FileReader::DetermineType() { - return Node::DetermineType(json); -} - -const std::string& FileReader::GetError() const { - return error; -} - -bool FileReader::loadFile(const std::string& filename, std::string& json) { - std::fstream file(filename.c_str(), std::ios::in | std::ios::binary); - - if (!file.is_open()) { - return false; - } - - file.seekg(0, std::ios::end); - std::ios::pos_type size = file.tellg(); - file.seekg(0, std::ios::beg); - - json.resize(static_cast(size), '\0'); - file.read(&json[0], size); - - return true; -} - -Writer::Writer(const Node& root, const Format& format) : fi(new FormatInterpreter), root(root) { - SetFormat(format); -} -Writer::~Writer() { - delete fi; - fi = nullptr; -} - -void Writer::SetFormat(const Format& format) { - fi->SetFormat(format); -} -const std::string& Writer::Write() { - result.clear(); - writeNode(root, 0); - return result; -} - -const std::string& Writer::GetResult() const { - return result; -} - -void Writer::writeNode(const Node& node, size_t level) { - switch (node.GetType()) { - case Node::T_OBJECT: - writeObject(node.AsObject(), level); - break; - case Node::T_ARRAY: - writeArray(node.AsArray(), level); - break; - case Node::T_VALUE: - writeValue(node.AsValue()); - break; - } -} -void Writer::writeObject(const Object& node, size_t level) { - result += "{" + fi->GetNewline(); - - for (auto it = node.begin(); it != node.end(); ++it) { - const std::string& name = (*it).first; - // const Node &value = (*it).second; - - if (it != node.begin()) - result += "," + fi->GetNewline(); - result += fi->GetIndentation(level + 1) + "\"" + name + "\"" + ":" + fi->GetSpacing(); - writeNode((*it).second, level + 1); - } - - result += fi->GetNewline() + fi->GetIndentation(level) + "}"; -} -void Writer::writeArray(const Array& node, size_t level) { - result += "[" + fi->GetNewline(); - - for (auto it = node.begin(); it != node.end(); ++it) { - const Node& value = (*it); - - if (it != node.begin()) - result += "," + fi->GetNewline(); - result += fi->GetIndentation(level + 1); - writeNode(value, level + 1); - } - - result += fi->GetNewline() + fi->GetIndentation(level) + "]"; -} -void Writer::writeValue(const Value& node) { - if (node.IsString()) { - result += "\"" + Value::EscapeString(node.ToString()) + "\""; - } else { - result += node.ToString(); - } -} - -Parser::Parser(Node& root) : root(root) { -} -Parser::Parser(Node& root, const std::string& json) : root(root) { - SetJson(json); -} - -void Parser::SetJson(const std::string& json) { - this->json = json; - jsonSize = json.size(); -} -bool Parser::Parse() { - cursor = 0; - - tokenize(); - bool success = assemble(); - - return success; -} - -const std::string& Parser::GetError() const { - return error; -} - -void Parser::tokenize() { - Token token = T_UNKNOWN; - std::string valueBuffer; - bool saveBuffer; - - for (; cursor < jsonSize; ++cursor) { - char c = json.at(cursor); - - if (IsWhitespace(c)) - continue; - - saveBuffer = true; - - switch (c) { - case '{': { - token = T_OBJ_BEGIN; - break; - } - case '}': { - token = T_OBJ_END; - break; - } - case '[': { - token = T_ARRAY_BEGIN; - break; - } - case ']': { - token = T_ARRAY_END; - break; - } - case ',': { - token = T_SEPARATOR_NODE; - break; - } - case ':': { - token = T_SEPARATOR_NAME; - break; - } - case '"': { - token = T_VALUE; - readString(); - break; - } - case '/': { - char p = peek(); - if (p == '*') { - jumpToCommentEnd(); - } else if (p == '/') { - jumpToNext('\n'); - } - break; - } - default: { - valueBuffer += c; - saveBuffer = false; - break; - } - } - - if ((saveBuffer || cursor == jsonSize - 1) && (!valueBuffer.empty())) // Always save buffer on the last character - { - if (interpretValue(valueBuffer)) { - tokens.push(T_VALUE); - } else { - // Store the unknown token, so we can show it to the user - data.emplace(Value::VT_STRING, valueBuffer); - tokens.push(T_UNKNOWN); - } - - valueBuffer.clear(); - } - - // Push the token last so that any - // value token will get pushed first - // from above. - // If saveBuffer is false, it means that - // we are in the middle of a value, so we - // don't want to push any tokens now. - if (saveBuffer) { - tokens.push(token); - } - } -} -bool Parser::assemble() { - std::stack> nodeStack; - - std::string name; - - Token token; - while (!tokens.empty()) { - token = tokens.front(); - tokens.pop(); - - switch (token) { - case T_UNKNOWN: { - const std::string& unknownToken = data.front().second; - error = "Unknown token: " + unknownToken; - data.pop(); - return false; - } - case T_OBJ_BEGIN: { - Node* node = nullptr; - if (nodeStack.empty()) { - if (!root.IsObject()) { - error = "The given root node is not an object"; - return false; - } - - node = &root; - } else { - node = new Object; - } - - nodeStack.emplace(name, node); - name.clear(); - break; - } - case T_ARRAY_BEGIN: { - Node* node = nullptr; - if (nodeStack.empty()) { - if (!root.IsArray()) { - error = "The given root node is not an array"; - return false; - } - - node = &root; - } else { - node = new Array; - } - - nodeStack.emplace(name, node); - name.clear(); - break; - } - case T_OBJ_END: - case T_ARRAY_END: { - if (nodeStack.empty()) { - error = "Found end of object or array without beginning"; - return false; - } - if (token == T_OBJ_END && !nodeStack.top().second->IsObject()) { - error = "Mismatched end and beginning of object"; - return false; - } - if (token == T_ARRAY_END && !nodeStack.top().second->IsArray()) { - error = "Mismatched end and beginning of array"; - return false; - } - - std::string name = nodeStack.top().first; - Node* node = nodeStack.top().second; - nodeStack.pop(); - - if (!nodeStack.empty()) { - if (nodeStack.top().second->IsObject()) { - nodeStack.top().second->AsObject().Add(name, *node); - } else if (nodeStack.top().second->IsArray()) { - nodeStack.top().second->AsArray().Add(*node); - } else { - error = "Can only add elements to objects and arrays"; - return false; - } - - delete node; - node = nullptr; - } - break; - } - case T_VALUE: { - if (!tokens.empty() && tokens.front() == T_SEPARATOR_NAME) { - tokens.pop(); - if (data.front().first != Value::VT_STRING) { - error = "A name has to be a string"; - return false; - } - name = data.front().second; - data.pop(); - } else { - Node* node = nullptr; - if (nodeStack.empty()) { - if (!root.IsValue()) { - error = "The given root node is not a value"; - return false; - } - - node = &root; - } else { - node = new Value; - } - - if (data.front().first == Value::VT_STRING) { - dynamic_cast(node)->Set(data.front().second); // This method calls UnescapeString() - } else { - dynamic_cast(node)->Set(data.front().first, data.front().second); - } - data.pop(); - - if (!nodeStack.empty()) { - if (nodeStack.top().second->IsObject()) - nodeStack.top().second->AsObject().Add(name, *node); - else if (nodeStack.top().second->IsArray()) - nodeStack.top().second->AsArray().Add(*node); - - delete node; - node = nullptr; - name.clear(); - } else { - nodeStack.emplace(name, node); - name.clear(); - } - } - break; - } - case T_SEPARATOR_NAME: - case T_SEPARATOR_NODE: - break; - } - } - - return true; -} - -char Parser::peek() { - if (cursor < jsonSize - 1) { - return json.at(cursor + 1); - } - return '\0'; -} -void Parser::jumpToNext(char c) { - ++cursor; - while (cursor < jsonSize && json.at(cursor) != c) - ++cursor; -} -void Parser::jumpToCommentEnd() { - ++cursor; - char c1 = '\0'; - for (; cursor < jsonSize; ++cursor) { - char c2 = json.at(cursor); - - if (c1 == '*' && c2 == '/') - break; - - c1 = c2; - } -} - -void Parser::readString() { - if (json.at(cursor) != '"') - return; - - std::string str; - - ++cursor; - - char c1 = '\0'; - for (; cursor < jsonSize; ++cursor) { - char c2 = json.at(cursor); - - if (c1 != '\\' && c2 == '"') { - break; - } - - str += c2; - - c1 = c2; - } - - data.emplace(Value::VT_STRING, str); -} -bool Parser::interpretValue(const std::string& value) { - std::string upperValue; - upperValue.reserve(value.size()); - std::transform(value.begin(), value.end(), upperValue.begin(), toupper); - - if (upperValue == "NULL") { - data.emplace(Value::VT_NULL, ""); - } else if (upperValue == "TRUE") { - data.emplace(Value::VT_BOOL, "true"); - } else if (upperValue == "FALSE") { - data.emplace(Value::VT_BOOL, "false"); - } else { - bool number = std::all_of(value.begin(), value.end(), IsNumber); - if (!number) { - return false; - } - data.emplace(Value::VT_NUMBER, value); - } - return true; -} -} // namespace Jzon diff --git a/samples/Jzon.h b/samples/Jzon.h deleted file mode 100644 index 13227656f2..0000000000 --- a/samples/Jzon.h +++ /dev/null @@ -1,517 +0,0 @@ -/* -Copyright (c) 2013 Johannes Häggqvist - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ -#ifndef Jzon_h__ -#define Jzon_h__ - -#ifndef JzonAPI -#ifdef _WINDLL -#define JzonAPI __declspec(dllimport) -#elif defined(__GNUC__) && (__GNUC__ >= 4) -#define JzonAPI __attribute__((visibility("default"))) -#else -#define JzonAPI -#endif -#endif - -#include -#include -#include -#include -#include - -namespace Jzon { -class Node; -class Value; -class Object; -class Array; -using NamedNode = std::pair; -using NamedNodePtr = std::pair; - -class TypeException : public std::logic_error { - public: - TypeException() : std::logic_error("A Node was used as the wrong type") { - } -}; -class NotFoundException : public std::out_of_range { - public: - NotFoundException() : std::out_of_range("The node could not be found") { - } -}; - -struct Format { - bool newline; - bool spacing; - bool useTabs; - unsigned int indentSize; -}; -static const Format StandardFormat = {true, true, true, 1}; -static const Format NoFormat = {false, false, false, 0}; - -class JzonAPI Node { - friend class Object; - friend class Array; - - public: - enum Type { T_OBJECT, T_ARRAY, T_VALUE }; - - Node() noexcept = default; - virtual ~Node() noexcept = default; - - virtual Type GetType() const = 0; - - inline bool IsObject() const { - return (GetType() == T_OBJECT); - } - inline bool IsArray() const { - return (GetType() == T_ARRAY); - } - inline bool IsValue() const { - return (GetType() == T_VALUE); - } - - Object& AsObject(); - const Object& AsObject() const; - Array& AsArray(); - const Array& AsArray() const; - Value& AsValue(); - const Value& AsValue() const; - - virtual inline bool IsNull() const { - return false; - } - virtual inline bool IsString() const { - return false; - } - virtual inline bool IsNumber() const { - return false; - } - virtual inline bool IsBool() const { - return false; - } - - virtual std::string ToString() const { - throw TypeException(); - } - virtual int ToInt() const { - throw TypeException(); - } - virtual float ToFloat() const { - throw TypeException(); - } - virtual double ToDouble() const { - throw TypeException(); - } - virtual bool ToBool() const { - throw TypeException(); - } - - virtual bool Has(const std::string& /*name*/) const { - throw TypeException(); - } - virtual size_t GetCount() const { - return 0; - } - virtual Node& Get(const std::string& /*name*/) const { - throw TypeException(); - } - virtual Node& Get(size_t /*index*/) const { - throw TypeException(); - } - - static Type DetermineType(const std::string& json); - - protected: - virtual Node* GetCopy() const = 0; -}; - -class JzonAPI Value : public Node { - public: - enum ValueType { VT_NULL, VT_STRING, VT_NUMBER, VT_BOOL }; - - Value(); - Value(const Value& rhs); - Value(const Node& rhs); - Value(ValueType type, const std::string& value); - Value(const std::string& value); - Value(const char* value); - Value(const int value); - Value(const float value); - Value(const double value); - Value(const bool value); - ~Value() override = default; - - Type GetType() const override; - ValueType GetValueType() const; - - inline bool IsNull() const override { - return (type == VT_NULL); - } - inline bool IsString() const override { - return (type == VT_STRING); - } - inline bool IsNumber() const override { - return (type == VT_NUMBER); - } - inline bool IsBool() const override { - return (type == VT_BOOL); - } - - std::string ToString() const override; - int ToInt() const override; - float ToFloat() const override; - double ToDouble() const override; - bool ToBool() const override; - - void SetNull(); - void Set(const Value& value); - void Set(ValueType type, const std::string& value); - void Set(const std::string& value); - void Set(const char* value); - void Set(const int value); - void Set(const float value); - void Set(const double value); - void Set(const bool value); - - Value& operator=(const Value& rhs); - Value& operator=(const Node& rhs); - Value& operator=(const std::string& rhs); - Value& operator=(const char* rhs); - Value& operator=(const int rhs); - Value& operator=(const float rhs); - Value& operator=(const double rhs); - Value& operator=(const bool rhs); - - bool operator==(const Value& other) const; - bool operator!=(const Value& other) const; - - static std::string EscapeString(const std::string& value); - static std::string UnescapeString(const std::string& value); - - protected: - Node* GetCopy() const override; - - private: - std::string valueStr; - ValueType type; -}; - -static const Value null; - -class JzonAPI Object : public Node { - public: - class iterator : public std::iterator { - public: - iterator(NamedNodePtr* o) : p(o) { - } - iterator(const iterator& it) : p(it.p) { - } - - iterator& operator++() { - ++p; - return *this; - } - iterator operator++(int) { - iterator tmp(*this); - operator++(); - return tmp; - } - - bool operator==(const iterator& rhs) { - return p == rhs.p; - } - bool operator!=(const iterator& rhs) { - return p != rhs.p; - } - - NamedNode operator*() { - return NamedNode(p->first, *p->second); - } - - private: - NamedNodePtr* p; - }; - class const_iterator : public std::iterator { - public: - const_iterator(const NamedNodePtr* o) : p(o) { - } - const_iterator(const const_iterator& it) : p(it.p) { - } - - const_iterator& operator++() { - ++p; - return *this; - } - const_iterator operator++(int) { - const_iterator tmp(*this); - operator++(); - return tmp; - } - - bool operator==(const const_iterator& rhs) { - return p == rhs.p; - } - bool operator!=(const const_iterator& rhs) { - return p != rhs.p; - } - - const NamedNode operator*() { - return NamedNode(p->first, *p->second); - } - - private: - const NamedNodePtr* p; - }; - - Object() = default; - Object(const Object& other); - Object(const Node& other); - ~Object() override; - - Type GetType() const override; - - void Add(const std::string& name, Node& node); - void Add(const std::string& name, const Value& node); - void Remove(const std::string& name); - void Clear(); - - iterator begin(); - const_iterator begin() const; - iterator end(); - const_iterator end() const; - - bool Has(const std::string& name) const override; - size_t GetCount() const override; - Node& Get(const std::string& name) const override; - using Node::Get; - - protected: - Node* GetCopy() const override; - - private: - using ChildList = std::vector; - ChildList children; -}; - -class JzonAPI Array : public Node { - public: - class iterator : public std::iterator { - public: - iterator(Node** o) : p(o) { - } - iterator(const iterator& it) : p(it.p) { - } - - iterator& operator++() { - ++p; - return *this; - } - iterator operator++(int) { - iterator tmp(*this); - operator++(); - return tmp; - } - - bool operator==(const iterator& rhs) { - return p == rhs.p; - } - bool operator!=(const iterator& rhs) { - return p != rhs.p; - } - - Node& operator*() { - return **p; - } - - private: - Node** p; - }; - class const_iterator : public std::iterator { - public: - const_iterator(const Node* const* o) : p(o) { - } - const_iterator(const const_iterator& it) : p(it.p) { - } - - const_iterator& operator++() { - ++p; - return *this; - } - const_iterator operator++(int) { - const_iterator tmp(*this); - operator++(); - return tmp; - } - - bool operator==(const const_iterator& rhs) { - return p == rhs.p; - } - bool operator!=(const const_iterator& rhs) { - return p != rhs.p; - } - - const Node& operator*() { - return **p; - } - - private: - const Node* const* p; - }; - - Array() = default; - Array(const Array& other); - Array(const Node& other); - ~Array() override; - - Type GetType() const override; - - void Add(Node& node); - void Add(const Value& node); - void Remove(size_t index); - void Clear(); - - iterator begin(); - const_iterator begin() const; - iterator end(); - const_iterator end() const; - - size_t GetCount() const override; - Node& Get(size_t index) const override; - using Node::Get; - - protected: - Node* GetCopy() const override; - - private: - using ChildList = std::vector; - ChildList children; -}; - -class JzonAPI FileWriter { - public: - FileWriter(std::string filename); - ~FileWriter() = default; - - static void WriteFile(const std::string& filename, const Node& root, const Format& format = NoFormat); - - void Write(const Node& root, const Format& format = NoFormat); - - private: - std::string filename; -}; - -class JzonAPI FileReader { - public: - FileReader(const std::string& filename); - ~FileReader() = default; - - static bool ReadFile(const std::string& filename, Node& node); - - bool Read(Node& node); - - Node::Type DetermineType(); - - const std::string& GetError() const; - - private: - static bool loadFile(const std::string& filename, std::string& json); - std::string json; - std::string error; -}; - -class JzonAPI Writer { - public: - Writer(const Node& root, const Format& format = NoFormat); - ~Writer(); - - void SetFormat(const Format& format); - const std::string& Write(); - - // Return result from last call to Write() - const std::string& GetResult() const; - - // Disable assignment operator - Writer& operator=(const Writer&) = delete; - - private: - void writeNode(const Node& node, size_t level); - void writeObject(const Object& node, size_t level); - void writeArray(const Array& node, size_t level); - void writeValue(const Value& node); - - std::string result; - - class FormatInterpreter* fi; - - const Node& root; -}; - -class JzonAPI Parser { - public: - Parser(Node& root); - Parser(Node& root, const std::string& json); - ~Parser() = default; - - void SetJson(const std::string& json); - bool Parse(); - - const std::string& GetError() const; - - // Disable assignment operator - Parser& operator=(const Parser&) = delete; - - private: - enum Token { - T_UNKNOWN, - T_OBJ_BEGIN, - T_OBJ_END, - T_ARRAY_BEGIN, - T_ARRAY_END, - T_SEPARATOR_NODE, - T_SEPARATOR_NAME, - T_VALUE - }; - - void tokenize(); - bool assemble(); - - char peek(); - void jumpToNext(char c); - void jumpToCommentEnd(); - - void readString(); - bool interpretValue(const std::string& value); - - std::string json; - std::size_t jsonSize{0}; - - std::queue tokens; - std::queue> data; - - std::size_t cursor{0}; - - Node& root; - - std::string error; -}; -} // namespace Jzon - -#endif // Jzon_h__ diff --git a/samples/exiv2json.cpp b/samples/exiv2json.cpp deleted file mode 100644 index cdd5b33103..0000000000 --- a/samples/exiv2json.cpp +++ /dev/null @@ -1,330 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Sample program to print metadata in JSON format - -#include - -#include - -#include -#include -#include - -#include "Jzon.h" - -#if defined(__MINGW32__) || defined(__MINGW64__) -#ifndef __MINGW__ -#define __MINGW__ -#endif -#endif - -struct Token { - std::string n; // the name eg "History" - bool a; // name is an array eg History[] - int i; // index (indexed from 1) eg History[1]/stEvt:action -}; -using Tokens = std::vector; - -// "XMP.xmp.MP.RegionInfo/MPRI:Regions[1]/MPReg:Rectangle" -bool getToken(std::string& in, Token& token, std::set* pNS = nullptr) { - bool result = false; - bool ns = false; - - token.n = ""; - token.a = false; - token.i = 0; - - while (!result && in.length()) { - std::string c = in.substr(0, 1); - char C = c.at(0); - in = in.substr(1, std::string::npos); - if (in.length() == 0 && C != ']') - token.n += c; - if (C == '/' || C == '[' || C == ':' || C == '.' || C == ']' || in.length() == 0) { - ns |= C == '/'; - token.a = C == '['; - if (C == ']') - token.i = std::atoi(token.n.c_str()); // encoded string first index == 1 - result = token.n.length() > 0; - } else { - token.n += c; - } - } - if (ns && pNS) - pNS->insert(token.n); - - return result; -} - -Jzon::Node& addToTree(Jzon::Node& r1, const Token& token) { - Jzon::Object object; - Jzon::Array array; - - std::string key = token.n; - size_t index = token.i - 1; // array Eg: "History[1]" indexed from 1. Jzon expects 0 based index. - auto& empty = token.a ? static_cast(array) : static_cast(object); - - if (r1.IsObject()) { - Jzon::Object& o1 = r1.AsObject(); - if (!o1.Has(key)) - o1.Add(key, empty); - return o1.Get(key); - } - if (r1.IsArray()) { - Jzon::Array& a1 = r1.AsArray(); - while (a1.GetCount() <= index) - a1.Add(empty); - return a1.Get(index); - } - return r1; -} - -Jzon::Node& recursivelyBuildTree(Jzon::Node& root, Tokens& tokens, size_t k) { - return addToTree(k == 0 ? root : recursivelyBuildTree(root, tokens, k - 1), tokens.at(k)); -} - -// build the json tree for this key. return location and discover the name -Jzon::Node& objectForKey(const std::string& Key, Jzon::Object& root, std::string& name, - std::set* pNS = nullptr) { - // Parse the key - Tokens tokens; - Token token; - std::string input = Key; // Example: "XMP.xmp.MP.RegionInfo/MPRI:Regions[1]/MPReg:Rectangle" - while (getToken(input, token, pNS)) - tokens.push_back(token); - size_t l = tokens.size() - 1; // leave leaf name to push() - name = tokens.at(l).n; - - // The second token. For example: XMP.dc is a namespace - if (pNS && tokens.size() > 1) - pNS->insert(tokens[1].n); - return recursivelyBuildTree(root, tokens, l - 1); - -#if 0 - // recursivelyBuildTree: - // Go to the root. Climb out adding objects or arrays to create the tree - // The leaf is pushed on the top by the caller of objectForKey() - // The recursion could be expressed by these if statements: - if ( l == 1 ) return addToTree(root,tokens[0]); - if ( l == 2 ) return addToTree(addToTree(root,tokens[0]),tokens[1]); - if ( l == 3 ) return addToTree(addToTree(addToTree(root,tokens[0]),tokens[1]),tokens[2]); - if ( l == 4 ) return addToTree(addToTree(addToTree(addToTree(root,tokens[0]),tokens[1]),tokens[2]),tokens[3]); - ... -#endif -} - -bool isObject(std::string& value) { - return value == std::string("type=\"Struct\""); -} - -bool isArray(std::string& value) { - return value == "type=\"Seq\"" || value == "type=\"Bag\"" || value == "type=\"Alt\""; -} - -#define STORE(node, key, value) \ - if (node.IsObject()) \ - node.AsObject().Add(key, value); \ - else \ - node.AsArray().Add(value) - -template -void push(Jzon::Node& node, const std::string& key, T i) { -#define ABORT_IF_I_EMPTY \ - if (i->value().size() == 0) { \ - return; \ - } - - std::string value = i->value().toString(); - - switch (i->typeId()) { - case Exiv2::xmpText: - if (::isObject(value)) { - Jzon::Object v; - STORE(node, key, v); - } else if (::isArray(value)) { - Jzon::Array v; - STORE(node, key, v); - } else { - STORE(node, key, value); - } - break; - - case Exiv2::unsignedByte: - case Exiv2::unsignedShort: - case Exiv2::unsignedLong: - case Exiv2::signedByte: - case Exiv2::signedShort: - case Exiv2::signedLong: - STORE(node, key, std::atoi(value.c_str())); - break; - - case Exiv2::tiffFloat: - case Exiv2::tiffDouble: - STORE(node, key, std::atof(value.c_str())); - break; - - case Exiv2::unsignedRational: - case Exiv2::signedRational: { - ABORT_IF_I_EMPTY - Jzon::Array arr; - Exiv2::Rational rat = i->value().toRational(); - arr.Add(rat.first); - arr.Add(rat.second); - STORE(node, key, arr); - } break; - - case Exiv2::langAlt: { - ABORT_IF_I_EMPTY - Jzon::Object l; - const auto& langs = dynamic_cast(i->value()); - for (auto&& lang : langs.value_) { - l.Add(lang.first, lang.second); - } - Jzon::Object o; - o.Add("lang", l); - STORE(node, key, o); - } break; - - default: - case Exiv2::date: - case Exiv2::time: - case Exiv2::asciiString: - case Exiv2::string: - case Exiv2::comment: - case Exiv2::undefined: - case Exiv2::tiffIfd: - case Exiv2::directory: - case Exiv2::xmpAlt: - case Exiv2::xmpBag: - case Exiv2::xmpSeq: - // http://dev.exiv2.org/boards/3/topics/1367#message-1373 - if (key == "UserComment") { - size_t pos = value.find('\0'); - if (pos != std::string::npos) - value = value.substr(0, pos); - } - if (key == "MakerNote") - return; - STORE(node, key, value); - break; - } -} - -void fileSystemPush(const char* path, Jzon::Node& nfs) { - auto& fs = dynamic_cast(nfs); - fs.Add("path", path); - fs.Add("realpath", std::filesystem::absolute(std::filesystem::path(path)).string()); - - struct stat buf = {}; - stat(path, &buf); - - fs.Add("st_dev", static_cast(buf.st_dev)); /* ID of device containing file */ - fs.Add("st_ino", static_cast(buf.st_ino)); /* inode number */ - fs.Add("st_mode", static_cast(buf.st_mode)); /* protection */ - fs.Add("st_nlink", static_cast(buf.st_nlink)); /* number of hard links */ - fs.Add("st_uid", static_cast(buf.st_uid)); /* user ID of owner */ - fs.Add("st_gid", static_cast(buf.st_gid)); /* group ID of owner */ - fs.Add("st_rdev", static_cast(buf.st_rdev)); /* device ID (if special file) */ - fs.Add("st_size", static_cast(buf.st_size)); /* total size, in bytes */ - fs.Add("st_atime", static_cast(buf.st_atime)); /* time of last access */ - fs.Add("st_mtime", static_cast(buf.st_mtime)); /* time of last modification */ - fs.Add("st_ctime", static_cast(buf.st_ctime)); /* time of last status change */ - -#if defined(_MSC_VER) || defined(__MINGW__) - size_t blksize = 1024; - size_t blocks = (buf.st_size + blksize - 1) / blksize; -#else - size_t blksize = buf.st_blksize; - size_t blocks = buf.st_blocks; -#endif - fs.Add("st_blksize", static_cast(blksize)); /* blocksize for file system I/O */ - fs.Add("st_blocks", static_cast(blocks)); /* number of 512B blocks allocated */ -} - -int main(int argc, char* const argv[]) { - Exiv2::XmpParser::initialize(); - ::atexit(Exiv2::XmpParser::terminate); -#ifdef EXV_ENABLE_BMFF - Exiv2::enableBMFF(); -#endif - - try { - if (argc < 2 || argc > 3) { - std::cout << "Usage: " << argv[0] << " [-option] file" << std::endl; - std::cout << "Option: all | exif | iptc | xmp | filesystem" << std::endl; - return EXIT_FAILURE; - } - const char* path = argv[argc - 1]; - const char* opt = argc == 3 ? argv[1] : "-all"; - while (opt[0] == '-') - opt++; // skip past leading -'s - char option = opt[0]; - - Exiv2::Image::UniquePtr image = Exiv2::ImageFactory::open(path); - image->readMetadata(); - - Jzon::Object root; - - if (option == 'f') { // only report filesystem when requested - const char* Fs = "FS"; - Jzon::Object fs; - root.Add(Fs, fs); - fileSystemPush(path, root.Get(Fs)); - } - - if (option == 'a' || option == 'e') { - Exiv2::ExifData& exifData = image->exifData(); - for (auto i = exifData.begin(); i != exifData.end(); ++i) { - std::string name; - Jzon::Node& object = objectForKey(i->key(), root, name); - push(object, name, i); - } - } - - if (option == 'a' || option == 'i') { - Exiv2::IptcData& iptcData = image->iptcData(); - for (auto i = iptcData.begin(); i != iptcData.end(); ++i) { - std::string name; - Jzon::Node& object = objectForKey(i->key(), root, name); - push(object, name, i); - } - } - -#ifdef EXV_HAVE_XMP_TOOLKIT - if (option == 'a' || option == 'x') { - Exiv2::XmpData& xmpData = image->xmpData(); - if (!xmpData.empty()) { - // get the xmpData and recursively parse into a Jzon Object - std::set namespaces; - for (auto i = xmpData.begin(); i != xmpData.end(); ++i) { - std::string name; - Jzon::Node& object = objectForKey(i->key(), root, name, &namespaces); - push(object, name, i); - } - - // get the namespace dictionary from XMP - Exiv2::Dictionary nsDict; - Exiv2::XmpProperties::registeredNamespaces(nsDict); - - // create and populate a Jzon::Object for the namespaces - Jzon::Object xmlns; - for (auto&& ns : namespaces) { - xmlns.Add(ns, nsDict[ns]); - } - - // add xmlns as Xmp.xmlns - root.Get("Xmp").AsObject().Add("xmlns", xmlns); - } - } -#endif - - Jzon::Writer writer(root, Jzon::StandardFormat); - writer.Write(); - std::cout << writer.GetResult() << std::endl; - return EXIT_SUCCESS; - } - - catch (Exiv2::Error& e) { - std::cout << "Caught Exiv2 exception '" << e.what() << "'\n"; - return EXIT_FAILURE; - } -} diff --git a/tests/bash_tests/test_issue_1054.py b/tests/bash_tests/test_issue_1054.py deleted file mode 100644 index 76f94e894d..0000000000 --- a/tests/bash_tests/test_issue_1054.py +++ /dev/null @@ -1,280 +0,0 @@ -# -*- coding: utf-8 -*- - -import system_tests - - -class Exiv2jsonRecursiveJsonTreeWithXMP(metaclass=system_tests.CaseMeta): - - url = "http://dev.exiv2.org/issues/1054" - - env = { - 'TZ': 'UTC' - } - - filename1 = system_tests.path("$data_path/BlueSquare.xmp") - filename2 = system_tests.path("$data_path/exiv2-bug784.jpg") - - commands = [ "$exiv2json $filename1", - "$exiv2json x $filename1", - "$exiv2json $filename2", - ] - - stdout = [ """{ - "Exif": { - "Image": { - "ImageWidth": 360, - "ImageLength": 216, - "Orientation": 1, - "XResolution": [ - 720000, - 10000 - ], - "YResolution": [ - 720000, - 10000 - ], - "ResolutionUnit": 2, - "DateTime": "2005:09:07 22:09:51", - "ImageDescription": "XMPFiles BlueSquare test file, created in Photoshop CS2, saved as .psd, .jpg, and .tif.", - "Make": "Nikon" - }, - "Photo": { - "ColorSpace": 1, - "PixelXDimension": 360, - "PixelYDimension": 216, - "DateTimeDigitized": "2005:09:07 22:07:40" - } - }, - "Iptc": { - "Application2": { - "ObjectName": "Blue Square Test File - .jpg", - "Keywords": "XMP", - "Keywords": "Blue Square", - "Keywords": "test file", - "Keywords": "Photoshop", - "Keywords": ".jpg", - "DigitizationDate": "2005-09-07", - "Caption": "XMPFiles BlueSquare test file, created in Photoshop CS2, saved as .psd, .jpg, and .tif." - }, - "Envelope": { - "CharacterSet": "%G" - } - }, - "Xmp": { - "dc": { - "format": "image\/jpeg", - "title": { - "lang": { - "x-default": "Blue Square Test File - .jpg", - "en-US": "Blue Square Test File - .jpg", - "de-CH": "Blaues Quadrat Test Datei - .jpg" - } - }, - "description": { - "lang": { - "x-default": "XMPFiles BlueSquare test file, created in Photoshop CS2, saved as .psd, .jpg, and .tif." - } - }, - "subject": "XMP, Blue Square, test file, Photoshop, .jpg" - }, - "xmp": { - "CreatorTool": "Adobe Photoshop CS2 Macintosh", - "CreateDate": "2005-09-07T15:07:40-07:00", - "ModifyDate": "2005-09-07T15:09:51-07:00", - "MetadataDate": "2006-04-10T13:37:10-07:00" - }, - "xmpMM": { - "DocumentID": "uuid:9A3B7F52214211DAB6308A7391270C13", - "InstanceID": "uuid:B59AC1B3214311DAB6308A7391270C13", - "DerivedFrom": { - "stRef": { - "instanceID": "uuid:9A3B7F4F214211DAB6308A7391270C13", - "documentID": "uuid:9A3B7F4E214211DAB6308A7391270C13" - } - } - }, - "photoshop": { - "ColorMode": "3", - "ICCProfile": "sRGB IEC61966-2.1" - }, - "tiff": { - "Orientation": "1", - "XResolution": "720000\/10000", - "YResolution": "720000\/10000", - "ResolutionUnit": "2", - "ImageWidth": "360", - "ImageLength": "216", - "NativeDigest": "256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;D0485928256FC8D17D036C26919E106D", - "Make": "Nikon", - "BitsPerSample": "8, 8, 8" - }, - "exif": { - "PixelXDimension": "360", - "PixelYDimension": "216", - "ColorSpace": "1", - "NativeDigest": "36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;76DBD9F0A5E7ED8F62B4CE8EFA6478B4" - }, - "xmlns": { - "DerivedFrom": "", - "dc": "http:\/\/purl.org\/dc\/elements\/1.1\/", - "exif": "http:\/\/ns.adobe.com\/exif\/1.0\/", - "photoshop": "http:\/\/ns.adobe.com\/photoshop\/1.0\/", - "tiff": "http:\/\/ns.adobe.com\/tiff\/1.0\/", - "xmp": "http:\/\/ns.adobe.com\/xap\/1.0\/", - "xmpMM": "http:\/\/ns.adobe.com\/xap\/1.0\/mm\/" - } - } -} -""", - """{ - "Xmp": { - "dc": { - "format": "image\/jpeg", - "title": { - "lang": { - "x-default": "Blue Square Test File - .jpg", - "en-US": "Blue Square Test File - .jpg", - "de-CH": "Blaues Quadrat Test Datei - .jpg" - } - }, - "description": { - "lang": { - "x-default": "XMPFiles BlueSquare test file, created in Photoshop CS2, saved as .psd, .jpg, and .tif." - } - }, - "subject": "XMP, Blue Square, test file, Photoshop, .jpg" - }, - "xmp": { - "CreatorTool": "Adobe Photoshop CS2 Macintosh", - "CreateDate": "2005-09-07T15:07:40-07:00", - "ModifyDate": "2005-09-07T15:09:51-07:00", - "MetadataDate": "2006-04-10T13:37:10-07:00" - }, - "xmpMM": { - "DocumentID": "uuid:9A3B7F52214211DAB6308A7391270C13", - "InstanceID": "uuid:B59AC1B3214311DAB6308A7391270C13", - "DerivedFrom": { - "stRef": { - "instanceID": "uuid:9A3B7F4F214211DAB6308A7391270C13", - "documentID": "uuid:9A3B7F4E214211DAB6308A7391270C13" - } - } - }, - "photoshop": { - "ColorMode": "3", - "ICCProfile": "sRGB IEC61966-2.1" - }, - "tiff": { - "Orientation": "1", - "XResolution": "720000\/10000", - "YResolution": "720000\/10000", - "ResolutionUnit": "2", - "ImageWidth": "360", - "ImageLength": "216", - "NativeDigest": "256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;D0485928256FC8D17D036C26919E106D", - "Make": "Nikon", - "BitsPerSample": "8, 8, 8" - }, - "exif": { - "PixelXDimension": "360", - "PixelYDimension": "216", - "ColorSpace": "1", - "NativeDigest": "36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;76DBD9F0A5E7ED8F62B4CE8EFA6478B4" - }, - "xmlns": { - "DerivedFrom": "", - "dc": "http:\/\/purl.org\/dc\/elements\/1.1\/", - "exif": "http:\/\/ns.adobe.com\/exif\/1.0\/", - "photoshop": "http:\/\/ns.adobe.com\/photoshop\/1.0\/", - "tiff": "http:\/\/ns.adobe.com\/tiff\/1.0\/", - "xmp": "http:\/\/ns.adobe.com\/xap\/1.0\/", - "xmpMM": "http:\/\/ns.adobe.com\/xap\/1.0\/mm\/" - } - } -} -""", - """{ - "Exif": { - "Image": { - "Orientation": 1, - "XResolution": [ - 72, - 1 - ], - "YResolution": [ - 72, - 1 - ], - "ResolutionUnit": 2, - "YCbCrPositioning": 1, - "Copyright": "Public Domain. Do whatever you like with this image", - "ExifTag": 232 - }, - "Photo": { - "ExifVersion": "48 50 50 49" - } - }, - "Iptc": { - "Envelope": { - "CharacterSet": "%G" - }, - "Application2": { - "RecordVersion": 4, - "Keywords": "1st", - "Keywords": "2nd", - "Keywords": "next1", - "Keywords": "next2", - "Keywords": "root", - "Keywords": "root0", - "Copyright": "Public Domain. Do whatever you like with this image" - } - }, - "Xmp": { - "dc": { - "format": "image\/jpeg", - "rights": { - "lang": { - "x-default": "Public Domain. Do whatever you like with this image" - } - }, - "subject": "1st, 2nd, next1, next2, root, root0" - }, - "xmpMM": { - "DocumentID": "004D48F936062EF5085A81BF96D4C494", - "OriginalDocumentID": "004D48F936062EF5085A81BF96D4C494", - "InstanceID": "xmp.iid:f74f0d02-e921-134e-8107-1dda17aad853", - "History": [ - { - "stEvt": { - "action": "saved", - "instanceID": "xmp.iid:f74f0d02-e921-134e-8107-1dda17aad853", - "when": "2015-03-24T20:35:55-05:00", - "softwareAgent": "Adobe Photoshop Lightroom 4.4 (Windows)", - "changed": "\/metadata" - } - } - ] - }, - "xmp": { - "MetadataDate": "2015-03-24T20:35:55-05:00" - }, - "crs": { - "RawFileName": "exiv2.lr.jpg" - }, - "lr": { - "hierarchicalSubject": "root0|next1|next2, root|1st|2nd" - }, - "xmlns": { - "crs": "http:\/\/ns.adobe.com\/camera-raw-settings\/1.0\/", - "dc": "http:\/\/purl.org\/dc\/elements\/1.1\/", - "lr": "http:\/\/ns.adobe.com\/lightroom\/1.0\/", - "stEvt": "http:\/\/ns.adobe.com\/xap\/1.0\/sType\/ResourceEvent#", - "xmp": "http:\/\/ns.adobe.com\/xap\/1.0\/", - "xmpMM": "http:\/\/ns.adobe.com\/xap\/1.0\/mm\/" - } - } -} -""" - ] - stderr = [""] * len(commands) - retval = [0] * len(commands) diff --git a/tests/bash_tests/test_issue_984.py b/tests/bash_tests/test_issue_984.py deleted file mode 100644 index fb7b839343..0000000000 --- a/tests/bash_tests/test_issue_984.py +++ /dev/null @@ -1,20 +0,0 @@ -import system_tests - - -class XMPMetaDeleteNamespace( - metaclass=system_tests.CaseMeta): - """ - Regression test for the bug described in: - https://github.com/Exiv2/exiv2/issues/984 - """ - url = "https://github.com/Exiv2/exiv2/issues/984" - - filename = system_tests.path( - "$data_path/issue_94_poc3.pgf" - ) - commands = ["$exiv2json $filename"] - stdout = ["""Caught Exiv2 exception 'XMP Toolkit error 9: Fatal namespace map problem' -"""] - stderr = ["""Warning: Removing 54 characters from the beginning of the XMP packet -"""] - retval = [1]