Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new MessagePack version of CJSON #1452

Merged
merged 6 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions avogadro/io/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ add_library(IO)
avogadro_headers(IO
cjsonformat.h
cmlformat.h
cmsgpackformat.h
dcdformat.h
fileformat.h
fileformatmanager.h
Expand All @@ -19,6 +20,7 @@ avogadro_headers(IO
target_sources(IO PRIVATE
cjsonformat.cpp
cmlformat.cpp
cmsgpackformat.cpp
dcdformat.cpp
fileformat.cpp
fileformatmanager.cpp
Expand Down
32 changes: 27 additions & 5 deletions avogadro/io/cjsonformat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,18 @@ bool isBooleanArray(json& j)

bool CjsonFormat::read(std::istream& file, Molecule& molecule)
{
json jsonRoot = json::parse(file, nullptr, false);
return deserialize(file, molecule, true);
}

bool CjsonFormat::deserialize(std::istream& file, Molecule& molecule,
bool isJson)
{
json jsonRoot;
if (isJson)
jsonRoot = json::parse(file, nullptr, false);
else // msgpack
jsonRoot = json::from_msgpack(file);

if (jsonRoot.is_discarded()) {
appendError("Error reading CJSON file.");
return false;
Expand Down Expand Up @@ -634,6 +645,12 @@ bool CjsonFormat::read(std::istream& file, Molecule& molecule)
}

bool CjsonFormat::write(std::ostream& file, const Molecule& molecule)
{
return serialize(file, molecule, true);
}

bool CjsonFormat::serialize(std::ostream& file, const Molecule& molecule,
bool isJson)
{
json opts;
if (!options().empty())
Expand Down Expand Up @@ -1015,7 +1032,8 @@ bool CjsonFormat::write(std::ostream& file, const Molecule& molecule)
modes.push_back(static_cast<unsigned int>(i) + 1);
freqs.push_back(molecule.vibrationFrequencies()[i]);
inten.push_back(molecule.vibrationIRIntensities()[i]);
raman.push_back(molecule.vibrationRamanIntensities()[i]);
if (molecule.vibrationRamanIntensities().size() > i)
raman.push_back(molecule.vibrationRamanIntensities()[i]);
Core::Array<Vector3> atomDisplacements = molecule.vibrationLx(i);
json eigenVector;
for (auto pos : atomDisplacements) {
Expand All @@ -1028,7 +1046,8 @@ bool CjsonFormat::write(std::ostream& file, const Molecule& molecule)
root["vibrations"]["modes"] = modes;
root["vibrations"]["frequencies"] = freqs;
root["vibrations"]["intensities"] = inten;
root["vibrations"]["ramanIntensities"] = raman;
if (molecule.vibrationRamanIntensities().size() > 0)
root["vibrations"]["ramanIntensities"] = raman;
root["vibrations"]["eigenVectors"] = eigenVectors;
}

Expand Down Expand Up @@ -1059,8 +1078,11 @@ bool CjsonFormat::write(std::ostream& file, const Molecule& molecule)
root["layer"]["settings"][settings.first] = setting;
}

// Write out the file, use a two space indent to "pretty print".
file << std::setw(2) << root;
if (isJson)
file << std::setw(2) << root;
else { // write msgpack
json::to_msgpack(root, file);
}

return true;
}
Expand Down
10 changes: 7 additions & 3 deletions avogadro/io/cjsonformat.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,21 @@ class AVOGADROIO_EXPORT CjsonFormat : public FileFormat

std::string specificationUrl() const override
{
return "http://wiki.openchemistry.org/Chemical_JSON";
return "https://github.com/openchemistry/chemicaljson";
}

std::vector<std::string> fileExtensions() const override;
std::vector<std::string> mimeTypes() const override;

bool read(std::istream& in, Core::Molecule& molecule) override;
bool write(std::ostream& out, const Core::Molecule& molecule) override;

// internal - to allow JSON or MsgPack to be written
bool deserialize(std::istream& in, Core::Molecule& molecule, bool json);
bool serialize(std::ostream& out, const Core::Molecule& molecule, bool json);
};

} // end Io namespace
} // end Avogadro namespace
} // namespace Io
} // namespace Avogadro

#endif // AVOGADRO_IO_CJSONFORMAT_H
45 changes: 45 additions & 0 deletions avogadro/io/cmsgpackformat.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/******************************************************************************
This source file is part of the Avogadro project.
This source code is released under the 3-Clause BSD License, (see "LICENSE").
******************************************************************************/

#include "cmsgpackformat.h"

#include <iostream>

using namespace std;

namespace Avogadro::Io {

CMsgPackFormat::CMsgPackFormat() : CjsonFormat()
{
m_json = false;
}

CMsgPackFormat::~CMsgPackFormat() = default;

vector<std::string> CMsgPackFormat::fileExtensions() const
{
vector<std::string> ext;
ext.emplace_back("cmpk");
return ext;
}

vector<std::string> CMsgPackFormat::mimeTypes() const
{
vector<std::string> mime;
mime.emplace_back("chemical/x-cmpack");
return mime;
}

bool CMsgPackFormat::read(std::istream& in, Core::Molecule& molecule)

Check notice on line 35 in avogadro/io/cmsgpackformat.cpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

avogadro/io/cmsgpackformat.cpp#L35

Check buffer boundaries if used in a loop including recursive loops (CWE-120, CWE-20).
{
return CjsonFormat::deserialize(in, molecule, false);
}

bool CMsgPackFormat::write(std::ostream& out, const Core::Molecule& molecule)
{
return CjsonFormat::serialize(out, molecule, false);
}

} // namespace Avogadro::Io
62 changes: 62 additions & 0 deletions avogadro/io/cmsgpackformat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/******************************************************************************
This source file is part of the Avogadro project.
This source code is released under the 3-Clause BSD License, (see "LICENSE").
******************************************************************************/

#ifndef AVOGADRO_IO_CMSGPACKFORMAT_H
#define AVOGADRO_IO_CMSGPACKFORMAT_H

#include "cjsonformat.h"
#include "fileformat.h"

namespace Avogadro {
namespace Core {
class GaussianSet;
}
namespace Io {

/**
* @class CMsgPackFormat cmsgpackformat.h <avogadro/io/cmsgpackformat.h>
* @brief Implementation of the Chemical MessagePack format.
*/

class AVOGADROIO_EXPORT CMsgPackFormat : public CjsonFormat
{
public:
CMsgPackFormat();
~CMsgPackFormat() override;

Operations supportedOperations() const override
{
return ReadWrite | File | Stream | String;
}

FileFormat* newInstance() const override { return new CMsgPackFormat; }
std::string identifier() const override { return "Avogadro: CMsgPack"; }
std::string name() const override { return "Chemical MessagePack"; }
std::string description() const override
{
return "CMsgPack format is a lightweight intermediate format used to "
"exchange "
"information between Avogadro and other data parsing applications";
}

std::string specificationUrl() const override
{
return "https://github.com/openchemistry/chemicaljson";
}

std::vector<std::string> fileExtensions() const override;
std::vector<std::string> mimeTypes() const override;

bool read(std::istream& in, Core::Molecule& molecule) override;

Check notice on line 52 in avogadro/io/cmsgpackformat.h

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

avogadro/io/cmsgpackformat.h#L52

Check buffer boundaries if used in a loop including recursive loops (CWE-120, CWE-20).
bool write(std::ostream& out, const Core::Molecule& molecule) override;

// write MessagePack
bool m_json = false;
};

} // namespace Io
} // namespace Avogadro

#endif // AVOGADRO_IO_CMSGPACKFORMAT_H
25 changes: 13 additions & 12 deletions avogadro/io/fileformatmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "cjsonformat.h"
#include "cmlformat.h"
#include "cmsgpackformat.h"
#include "dcdformat.h"
#include "gromacsformat.h"
#include "lammpsformat.h"
Expand Down Expand Up @@ -134,7 +135,7 @@ bool FileFormatManager::addFormat(FileFormat* format)
appendError("Format " + format->identifier() + " already loaded.");
return false;
}
for (auto & m_format : m_formats) {
for (auto& m_format : m_formats) {
if (m_format == format) {
appendError("The format object was already loaded.");
return false;
Expand All @@ -146,11 +147,11 @@ bool FileFormatManager::addFormat(FileFormat* format)
m_formats.push_back(format);
m_identifiers[format->identifier()].push_back(index);
std::vector<std::string> mimes = format->mimeTypes();
for (auto & mime : mimes) {
for (auto& mime : mimes) {
m_mimeTypes[mime].push_back(index);
}
std::vector<std::string> extensions = format->fileExtensions();
for (auto & extension : extensions) {
for (auto& extension : extensions) {
m_fileExtensions[extension].push_back(index);
}

Expand All @@ -160,7 +161,7 @@ bool FileFormatManager::addFormat(FileFormat* format)
namespace {
// Lookup each key from "keys" in "map", and remove "val" from the Map's
// data value (which is a vector of ValueType)
template<typename Map, typename VectorOfKeys, typename ValueType>
template <typename Map, typename VectorOfKeys, typename ValueType>
void removeFromMap(Map& map, const VectorOfKeys& keys, const ValueType& val)
{
for (auto key = keys.begin(), keyEnd = keys.end(); key != keyEnd; ++key) {
Expand All @@ -171,13 +172,12 @@ void removeFromMap(Map& map, const VectorOfKeys& keys, const ValueType& val)
if (vec.size() <= 1) {
map.erase(*key);
} else {
auto newEnd =
std::remove(vec.begin(), vec.end(), val);
auto newEnd = std::remove(vec.begin(), vec.end(), val);
vec.resize(newEnd - vec.begin());
}
}
}
}
} // namespace

bool FileFormatManager::removeFormat(const std::string& identifier)
{
Expand Down Expand Up @@ -284,6 +284,7 @@ FileFormatManager::FileFormatManager()
{
addFormat(new CmlFormat);
addFormat(new CjsonFormat);
addFormat(new CMsgPackFormat);
addFormat(new DcdFormat);
addFormat(new GromacsFormat);
addFormat(new LammpsTrajectoryFormat);
Expand All @@ -303,7 +304,7 @@ FileFormatManager::FileFormatManager()
FileFormatManager::~FileFormatManager()
{
// Delete the file formats that were loaded.
for (auto & m_format : m_formats) {
for (auto& m_format : m_formats) {
delete m_format;
}
m_formats.clear();
Expand All @@ -314,9 +315,9 @@ std::vector<std::string> FileFormatManager::filteredKeysFromFormatMap(
const FileFormatManager::FormatIdMap& fmap) const
{
std::vector<std::string> result;
for (const auto & it : fmap) {
for (auto formatIt = it.second.begin();
formatIt != it.second.end(); ++formatIt) {
for (const auto& it : fmap) {
for (auto formatIt = it.second.begin(); formatIt != it.second.end();
++formatIt) {
if (filter == FileFormat::None ||
(m_formats[*formatIt]->supportedOperations() & filter) == filter) {
result.push_back(it.first);
Expand Down Expand Up @@ -383,4 +384,4 @@ void FileFormatManager::appendError(const std::string& errorMessage)
m_error += errorMessage + "\n";
}

} // end Avogadro namespace
} // namespace Avogadro::Io
Loading