Fix Tux walking backwards after automatic backflipping, fixes #1063
[supertux.git] / src / addon / addon.cpp
index ff3ea21..2688422 100644 (file)
@@ -1,12 +1,11 @@
-//  $Id$
-//
 //  SuperTux - Add-on
 //  Copyright (C) 2007 Christoph Sommer <christoph.sommer@2007.expires.deltadevelopment.de>
+//                2014 Ingo Ruhnke <grumbel@gmail.com>
 //
-//  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 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 3 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
 //  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., 59 Temple Place - Suite 330, Boston, MA
-//  02111-1307, USA.
-//
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-#include <string>
-#include <sstream>
-#include <stdexcept>
-#include <physfs.h>
-#include "lisp/lisp.hpp"
-#include "lisp/writer.hpp"
-#include "lisp/parser.hpp"
 #include "addon/addon.hpp"
-#include "log.hpp"
-#include "addon/md5.hpp"
 
-std::string
-Addon::get_md5() const
-{
-  if (!installed) {
-    if (stored_md5 == "") log_warning << "Add-on not installed and no stored MD5 available" << std::endl;
-    return stored_md5;
-  }
+#include <physfs.h>
+#include <stdexcept>
+#include <sstream>
 
-  if (calculated_md5 != "") return calculated_md5;
+#include "lisp/parser.hpp"
+#include "util/reader.hpp"
+#include "util/writer.hpp"
+#include "util/log.hpp"
 
-  if (installed_physfs_filename == "") throw std::runtime_error("Tried to calculate MD5 of Add-on with unknown filename");
+namespace {
 
-  // TODO: this does not work as expected for some files -- IFileStream seems to not always behave like an ifstream.
-  //IFileStream ifs(installed_physfs_filename);
-  //std::string md5 = MD5(ifs).hex_digest();
+static const char* s_allowed_characters = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
 
-  MD5 md5;
-  PHYSFS_file* file;
-  file = PHYSFS_openRead(installed_physfs_filename.c_str());
-  unsigned char buffer[1024];
-  while (true) {
-    PHYSFS_sint64 len = PHYSFS_read(file, buffer, 1, sizeof(buffer));
-    if (len <= 0) break;
-    md5.update(buffer, len);
+Addon::Type addon_type_from_string(const std::string& type)
+{
+  if (type == "world")
+  {
+    return Addon::WORLD;
+  }
+  else if (type == "worldmap")
+  {
+    return Addon::WORLDMAP;
+  }
+  else if (type == "levelset")
+  {
+    return Addon::LEVELSET;
+  }
+  else
+  {
+    throw std::runtime_error("not a valid Addon::Type: " + type);
   }
-  PHYSFS_close(file);
-
-  calculated_md5 = md5.hex_digest();
-  log_debug << "MD5 of " << title << ": " << calculated_md5 << std::endl;
-
-  return calculated_md5;
 }
 
-void
-Addon::parse(const lisp::Lisp& lisp)
+} // namespace
+
+std::unique_ptr<Addon>
+Addon::parse(const Reader& lisp)
 {
-  try {
-    lisp.get("kind", kind);  
-    lisp.get("title", title);
-    lisp.get("author", author);
-    lisp.get("license", license);
-    lisp.get("http-url", http_url);
-    lisp.get("file", suggested_filename);
-    lisp.get("md5", stored_md5);
-  } catch(std::exception& e) {
+  std::unique_ptr<Addon> addon(new Addon);
+
+  try
+  {
+    if (!lisp.get("id", addon->m_id))
+    {
+      throw std::runtime_error("(id ...) field missing from addon description");
+    }
+
+    if (addon->m_id.empty())
+    {
+      throw std::runtime_error("addon id is empty");
+    }
+
+    if (addon->m_id.find_first_not_of(s_allowed_characters) != std::string::npos)
+    {
+      throw std::runtime_error("addon id contains illegal characters: " + addon->m_id);
+    }
+
+    lisp.get("version", addon->m_version);
+
+    std::string type;
+    lisp.get("type", type);
+    addon->m_type = addon_type_from_string(type);
+
+    lisp.get("title", addon->m_title);
+    lisp.get("author", addon->m_author);
+    lisp.get("license", addon->m_license);
+    lisp.get("url", addon->m_url);
+    lisp.get("md5", addon->m_md5);
+
+    return addon;
+  }
+  catch(const std::exception& err)
+  {
     std::stringstream msg;
-    msg << "Problem when parsing addoninfo: " << e.what();
+    msg << "Problem when parsing addoninfo: " << err.what();
     throw std::runtime_error(msg.str());
   }
 }
 
-void
-Addon::parse(std::string fname)
+std::unique_ptr<Addon>
+Addon::parse(const std::string& fname)
 {
-  try {
+  try
+  {
     lisp::Parser parser;
     const lisp::Lisp* root = parser.parse(fname);
     const lisp::Lisp* addon = root->get_lisp("supertux-addoninfo");
-    if(!addon) throw std::runtime_error("file is not a supertux-addoninfo file.");
-    parse(*addon);
-  } catch(std::exception& e) {
+    if(!addon)
+    {
+      throw std::runtime_error("file is not a supertux-addoninfo file.");
+    }
+    else
+    {
+      return parse(*addon);
+    }
+  }
+  catch(const std::exception& err)
+  {
     std::stringstream msg;
-    msg << "Problem when reading addoninfo '" << fname << "': " << e.what();
+    msg << "Problem when reading addoninfo '" << fname << "': " << err.what();
     throw std::runtime_error(msg.str());
   }
 }
 
-void
-Addon::write(lisp::Writer& writer) const
+Addon::Addon() :
+  m_id(),
+  m_version(0),
+  m_type(),
+  m_title(),
+  m_author(),
+  m_license(),
+  m_url(),
+  m_md5(),
+  m_install_filename(),
+  m_enabled(false)
+{}
+
+std::string
+Addon::get_filename() const
 {
-  writer.start_list("supertux-addoninfo");
-  if (kind != "") writer.write_string("kind", kind);  
-  if (title != "") writer.write_string("title", title);
-  if (author != "") writer.write_string("author", author);
-  if (license != "") writer.write_string("license", license);
-  if (http_url != "") writer.write_string("http-url", http_url);
-  if (suggested_filename != "") writer.write_string("file", suggested_filename);
-  if (stored_md5 != "") writer.write_string("md5", stored_md5);
-  writer.end_list("supertux-addoninfo");
+  return get_id() + ".zip";
 }
 
-void 
-Addon::write(std::string fname) const
+std::string
+Addon::get_install_filename() const
 {
-  lisp::Writer writer(fname);
-  write(writer);
+  return m_install_filename;
 }
 
-bool 
-Addon::operator==(Addon addon2) const
+bool
+Addon::is_installed() const
 {
-  std::string s1 = this->get_md5();
-  std::string s2 = addon2.get_md5();
+  return !m_install_filename.empty();
+}
 
-  if ((s1 != "") && (s2 != "")) return (s1 == s2);
+bool
+Addon::is_enabled() const
+{
+  return m_enabled;
+}
 
-  if (this->title != addon2.title) return false;
-  if (this->author != addon2.author) return false;
-  if (this->kind != addon2.kind) return false;
-  return true; 
+void
+Addon::set_install_filename(const std::string& absolute_filename, const std::string& md5)
+{
+  m_install_filename = absolute_filename;
+  m_md5 = md5;
 }
 
+void
+Addon::set_enabled(bool v)
+{
+  m_enabled = v;
+}
+
+
+/* EOF */