klayout/src/lay/laySaltGrain.cc

419 lines
8.9 KiB
C++

/*
KLayout Layout Viewer
Copyright (C) 2006-2017 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "laySaltGrain.h"
#include "tlString.h"
#include "tlXMLParser.h"
#include "tlHttpStream.h"
#include <QDir>
#include <QFileInfo>
#include <QBuffer>
#include <QResource>
namespace lay
{
static const std::string grain_filename = "grain.xml";
SaltGrain::SaltGrain ()
{
// .. nothing yet ..
}
bool
SaltGrain::operator== (const SaltGrain &other) const
{
return m_name == other.m_name &&
m_path == other.m_path &&
m_version == other.m_version &&
m_url == other.m_url &&
m_title == other.m_title &&
m_doc == other.m_doc &&
m_doc_url == other.m_doc_url &&
m_icon == other.m_icon &&
m_screenshot == other.m_screenshot &&
m_dependencies == other.m_dependencies &&
m_author == other.m_author &&
m_author_contact == other.m_author_contact &&
m_license == other.m_license &&
m_authored_time == other.m_authored_time &&
m_installed_time == other.m_installed_time;
}
void
SaltGrain::set_name (const std::string &n)
{
m_name = n;
}
void
SaltGrain::set_version (const std::string &v)
{
m_version = v;
}
void
SaltGrain::set_path (const std::string &p)
{
m_path = p;
}
void
SaltGrain::set_url (const std::string &u)
{
m_url = u;
}
void
SaltGrain::set_title (const std::string &t)
{
m_title = t;
}
void
SaltGrain::set_doc (const std::string &t)
{
m_doc = t;
}
void
SaltGrain::set_doc_url (const std::string &u)
{
m_doc_url = u;
}
void
SaltGrain::set_author (const std::string &a)
{
m_author = a;
}
void
SaltGrain::set_author_contact (const std::string &a)
{
m_author_contact = a;
}
void
SaltGrain::set_license (const std::string &l)
{
m_license = l;
}
void
SaltGrain::set_authored_time (const QDateTime &t)
{
m_authored_time = t;
}
void
SaltGrain::set_installed_time (const QDateTime &t)
{
m_installed_time = t;
}
void
SaltGrain::set_screenshot (const QImage &i)
{
m_screenshot = i;
}
void
SaltGrain::set_icon (const QImage &i)
{
m_icon = i;
}
int
SaltGrain::compare_versions (const std::string &v1, const std::string &v2)
{
tl::Extractor ex1 (v1.c_str ());
tl::Extractor ex2 (v2.c_str ());
while (true) {
if (ex1.at_end () && ex2.at_end ()) {
return 0;
}
int n1 = 0, n2 = 0;
if (! ex1.at_end ()) {
ex1.try_read (n1);
}
if (! ex2.at_end ()) {
ex2.try_read (n2);
}
if (n1 != n2) {
return n1 < n2 ? -1 : 1;
}
while (! ex1.at_end ()) {
char c = *ex1;
++ex1;
if (c == '.') {
break;
}
}
while (! ex2.at_end ()) {
char c = *ex2;
++ex2;
if (c == '.') {
break;
}
}
}
}
std::string
SaltGrain::spec_url (const std::string &url)
{
std::string res = url;
if (! res.empty()) {
if (res [res.size () - 1] != '/') {
res += "/";
}
res += grain_filename;
}
return res;
}
bool
SaltGrain::valid_name (const std::string &n)
{
std::string res;
tl::Extractor ex (n);
std::string s;
if (! ex.try_read_word (s, "_")) {
return false;
}
res += s;
while (! ex.at_end ()) {
if (! ex.test ("/")) {
return false;
}
if (! ex.try_read_word (s, "_")) {
return false;
}
res += "/";
res += s;
}
// this captures the cases where the extractor skips blanks
// TODO: the extractor should have a "non-blank-skipping" mode
return res == n;
}
bool
SaltGrain::valid_version (const std::string &v)
{
tl::Extractor ex (v.c_str ());
while (! ex.at_end ()) {
int n = 0;
if (! ex.try_read (n)) {
return false;
}
if (! ex.at_end ()) {
if (*ex != '.') {
return false;
} else {
++ex;
}
}
}
return true;
}
struct TimeConverter
{
std::string to_string (const QDateTime &time) const
{
if (time.isNull ()) {
return std::string ();
} else {
return tl::to_string (time.toString (Qt::ISODate));
}
}
void from_string (const std::string &time, QDateTime &res) const
{
if (time.empty ()) {
res = QDateTime ();
} else {
res = QDateTime::fromString (tl::to_qstring (time), Qt::ISODate);
}
}
};
struct ImageConverter
{
std::string to_string (const QImage &image) const
{
if (image.isNull ()) {
return std::string ();
} else {
QBuffer buffer;
buffer.open (QIODevice::WriteOnly);
image.save (&buffer, "PNG");
buffer.close ();
return buffer.buffer ().toBase64 ().constData ();
}
}
void from_string (const std::string &image, QImage &res) const
{
if (image.empty ()) {
res = QImage ();
} else {
res = QImage::fromData (QByteArray::fromBase64 (QByteArray (image.c_str (), image.size ())));
}
}
};
static tl::XMLElementList s_xml_elements =
tl::make_member (&SaltGrain::name, &SaltGrain::set_name, "name") +
tl::make_member (&SaltGrain::version, &SaltGrain::set_version, "version") +
tl::make_member (&SaltGrain::title, &SaltGrain::set_title, "title") +
tl::make_member (&SaltGrain::doc, &SaltGrain::set_doc, "doc") +
tl::make_member (&SaltGrain::doc_url, &SaltGrain::set_doc_url, "doc-url") +
tl::make_member (&SaltGrain::url, &SaltGrain::set_url, "url") +
tl::make_member (&SaltGrain::license, &SaltGrain::set_license, "license") +
tl::make_member (&SaltGrain::author, &SaltGrain::set_author, "author") +
tl::make_member (&SaltGrain::author_contact, &SaltGrain::set_author_contact, "author-contact") +
tl::make_member (&SaltGrain::authored_time, &SaltGrain::set_authored_time, "authored-time", TimeConverter ()) +
tl::make_member (&SaltGrain::installed_time, &SaltGrain::set_installed_time, "installed-time", TimeConverter ()) +
tl::make_member (&SaltGrain::icon, &SaltGrain::set_icon, "icon", ImageConverter ()) +
tl::make_member (&SaltGrain::screenshot, &SaltGrain::set_screenshot, "screenshot", ImageConverter ()) +
tl::make_element (&SaltGrain::begin_dependencies, &SaltGrain::end_dependencies, &SaltGrain::add_dependency, "depends",
tl::make_member (&SaltGrain::Dependency::name, "name") +
tl::make_member (&SaltGrain::Dependency::url, "url") +
tl::make_member (&SaltGrain::Dependency::version, "version")
);
static tl::XMLStruct<lay::SaltGrain> s_xml_struct ("salt-grain", s_xml_elements);
tl::XMLElementList &
SaltGrain::xml_struct ()
{
return s_xml_elements;
}
bool
SaltGrain::is_readonly () const
{
return !QFileInfo (tl::to_qstring (path ())).isWritable ();
}
void
SaltGrain::load (const std::string &p)
{
tl_assert (!p.empty ());
if (p[0] != ':') {
tl::XMLFileSource source (p);
s_xml_struct.parse (source, *this);
} else {
QResource res (tl::to_qstring (p));
QByteArray data;
if (res.isCompressed ()) {
data = qUncompress ((const unsigned char *)res.data (), (int)res.size ());
} else {
data = QByteArray ((const char *)res.data (), (int)res.size ());
}
std::string str_data (data.constData (), data.size ());
tl::XMLStringSource source (str_data);
s_xml_struct.parse (source, *this);
}
}
void
SaltGrain::load (tl::InputStream &p)
{
tl::XMLStreamSource source (p);
s_xml_struct.parse (source, *this);
}
void
SaltGrain::save () const
{
save (tl::to_string (QDir (tl::to_qstring (path ())).filePath (tl::to_qstring (grain_filename))));
}
void
SaltGrain::save (const std::string &p) const
{
tl::OutputStream os (p, tl::OutputStream::OM_Plain);
s_xml_struct.write (os, *this);
}
SaltGrain
SaltGrain::from_path (const std::string &path)
{
QDir dir (tl::to_qstring (path));
SaltGrain g;
g.load (tl::to_string (dir.filePath (tl::to_qstring (grain_filename))));
g.set_path (tl::to_string (dir.absolutePath ()));
return g;
}
SaltGrain
SaltGrain::from_url (const std::string &url)
{
tl::InputHttpStream http (SaltGrain::spec_url (url));
tl::InputStream stream (http);
SaltGrain g;
g.load (stream);
g.set_url (url);
return g;
}
bool
SaltGrain::is_grain (const std::string &path)
{
tl_assert (! path.empty ());
if (path[0] != ':') {
QDir dir (tl::to_qstring (path));
QString gf = dir.filePath (tl::to_qstring (grain_filename));
return QFileInfo (gf).exists ();
} else {
return QResource (tl::to_qstring (path + "/" + grain_filename)).isValid ();
}
}
}