A first try at error handling in the Downloader
[supertux.git] / src / addon / addon.cpp
index 0bbe885..2688422 100644 (file)
@@ -1,5 +1,6 @@
 //  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
 #include <stdexcept>
 #include <sstream>
 
-#include "addon/md5.hpp"
 #include "lisp/parser.hpp"
 #include "util/reader.hpp"
 #include "util/writer.hpp"
 #include "util/log.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;
-  }
-
-  if (calculated_md5 != "") return calculated_md5;
+namespace {
 
-  if (installed_physfs_filename == "") throw std::runtime_error("Tried to calculate MD5 of Add-on with unknown filename");
+static const char* s_allowed_characters = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
 
-  // 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();
-
-  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
+} // 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("kind", kind);  
-  if (title != "") writer.write("title", title);
-  if (author != "") writer.write("author", author);
-  if (license != "") writer.write("license", license);
-  if (http_url != "") writer.write("http-url", http_url);
-  if (suggested_filename != "") writer.write("file", suggested_filename);
-  if (stored_md5 != "") writer.write("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 */