--- /dev/null
+// system headers
+#include <cassert>
+#include <fstream>
+
+// local headers
+#include "includes/desktopfile_exceptions.h"
+#include "includes/desktopfile.h"
+#include "includes/desktopfilereader.h"
+#include "includes/desktopfilewriter.h"
+
+namespace linuxdeploy {
+ namespace desktopfile {
+ class DesktopFile::PrivateData {
+ public:
+ std::string path;
+ sections_t data;
+
+ public:
+ PrivateData() = default;
+
+ void copyData(const std::shared_ptr<PrivateData>& other) {
+ path = other->path;
+ data = other->data;
+ }
+
+ public:
+ bool isEmpty() const {
+ return data.empty();
+ }
+ };
+
+ DesktopFile::DesktopFile() : d(std::make_shared<PrivateData>()) {}
+
+ DesktopFile::DesktopFile(const std::string& path) : DesktopFile() {
+ // if the file doesn't exist, an exception shall be thrown
+ // otherwise, a user cannot know for sure whether a file was actually read (would need to check this
+ // manually beforehand
+ {
+ std::ifstream ifs(path);
+ if (!ifs) {
+ throw IOError("Could not find file " + path);
+ }
+ }
+
+ // will throw exceptions in case of issues
+ read(path);
+ };
+
+ DesktopFile::DesktopFile(std::istream& is) : DesktopFile() {
+ // will throw exceptions in case of issues
+ read(is);
+ };
+
+ // copy constructor
+ DesktopFile::DesktopFile(const DesktopFile& other) : DesktopFile() {
+ d->copyData(other.d);
+ }
+
+ // copy assignment constructor
+ DesktopFile& DesktopFile::operator=(const DesktopFile& other) {
+ if (this != &other) {
+ d->copyData(other.d);
+ }
+
+ return *this;
+ }
+
+ // move assignment operator
+ DesktopFile& DesktopFile::operator=(DesktopFile&& other) noexcept {
+ if (this != &other) {
+ d = other.d;
+ other.d = nullptr;
+ }
+ return *this;
+ }
+
+ void DesktopFile::read(const std::string& path) {
+ setPath(path);
+
+ // clear data before reading a new file
+ clear();
+
+ DesktopFileReader reader(path);
+ d->data = std::move(reader.data());
+ }
+
+ void DesktopFile::read(std::istream& is) {
+ // clear data before reading a new file
+ clear();
+
+ DesktopFileReader reader(is);
+ d->data = reader.data();
+ }
+
+ std::string DesktopFile::path() const {
+ return d->path;
+ }
+
+ void DesktopFile::setPath(const std::string& path) {
+ d->path = path;
+ }
+
+ bool DesktopFile::isEmpty() const {
+ return d->isEmpty();
+ }
+
+ void DesktopFile::clear() {
+ d->data.clear();
+ }
+
+ bool DesktopFile::save() const {
+ return save(d->path);
+ }
+
+ bool DesktopFile::save(const std::string& path) const {
+ DesktopFileWriter writer(d->data);
+ writer.save(path);
+
+ return true;
+ }
+
+ bool DesktopFile::save(std::ostream& os) const {
+ DesktopFileWriter writer(d->data);
+ writer.save(os);
+
+ return true;
+ }
+
+ bool DesktopFile::entryExists(const std::string& section, const std::string& key) const {
+ auto it = d->data.find(section);
+ if (it == d->data.end())
+ return false;
+
+ return (it->second.find(key) != it->second.end());
+ }
+
+ bool DesktopFile::setEntry(const std::string& section, const DesktopFileEntry& entry) {
+ // check if value exists -- used for return value
+ auto rv = entryExists(section, entry.key());
+
+ d->data[section][entry.key()] = entry;
+
+ return rv;
+ }
+
+ bool DesktopFile::setEntry(const std::string& section, DesktopFileEntry&& entry) {
+ // check if value exists -- used for return value
+ auto rv = entryExists(section, entry.key());
+
+ d->data[section][entry.key()] = entry;
+
+ return rv;
+ }
+
+ bool DesktopFile::getEntry(const std::string& section, const std::string& key, DesktopFileEntry& entry) const {
+ if (!entryExists(section, key))
+ return false;
+
+ entry = d->data[section][key];
+
+ // make sure keys are equal
+ assert(key == entry.key());
+
+ return true;
+ }
+
+ bool DesktopFile::validate() const {
+ // FIXME: call desktop-file-validate
+ return true;
+ }
+
+ bool operator==(const DesktopFile& first, const DesktopFile& second) {
+ return first.d->path == second.d->path && first.d->data == second.d->data;
+ }
+
+ bool operator !=(const DesktopFile& first, const DesktopFile& second) {
+ return !operator==(first, second);
+ }
+ }
+}
+
+
+