Updated email address, grumbel@gmx.de -> grumbel@gmail.com
[supertux.git] / src / addon / addon.cpp
1 //  SuperTux - Add-on
2 //  Copyright (C) 2007 Christoph Sommer <christoph.sommer@2007.expires.deltadevelopment.de>
3 //
4 //  This program is free software: you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation, either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 #include "addon/addon.hpp"
18
19 #include <physfs.h>
20 #include <stdexcept>
21 #include <sstream>
22
23 #include "addon/md5.hpp"
24 #include "lisp/parser.hpp"
25 #include "util/reader.hpp"
26 #include "util/writer.hpp"
27 #include "util/log.hpp"
28
29 std::string
30 Addon::get_md5() const
31 {
32   if (!installed) {
33     if (stored_md5 == "") log_warning << "Add-on not installed and no stored MD5 available" << std::endl;
34     return stored_md5;
35   }
36
37   if (calculated_md5 != "") return calculated_md5;
38
39   if (installed_physfs_filename == "") throw std::runtime_error("Tried to calculate MD5 of Add-on with unknown filename");
40
41   // TODO: this does not work as expected for some files -- IFileStream seems to not always behave like an ifstream.
42   //IFileStream ifs(installed_physfs_filename);
43   //std::string md5 = MD5(ifs).hex_digest();
44
45   MD5 md5;
46   PHYSFS_file* file;
47   file = PHYSFS_openRead(installed_physfs_filename.c_str());
48   unsigned char buffer[1024];
49   while (true) {
50     PHYSFS_sint64 len = PHYSFS_read(file, buffer, 1, sizeof(buffer));
51     if (len <= 0) break;
52     md5.update(buffer, len);
53   }
54   PHYSFS_close(file);
55
56   calculated_md5 = md5.hex_digest();
57   log_debug << "MD5 of " << title << ": " << calculated_md5 << std::endl;
58
59   return calculated_md5;
60 }
61
62 void
63 Addon::parse(const Reader& lisp)
64 {
65   try {
66     lisp.get("kind", kind);  
67     lisp.get("title", title);
68     lisp.get("author", author);
69     lisp.get("license", license);
70     lisp.get("http-url", http_url);
71     lisp.get("file", suggested_filename);
72     lisp.get("md5", stored_md5);
73   } catch(std::exception& e) {
74     std::stringstream msg;
75     msg << "Problem when parsing addoninfo: " << e.what();
76     throw std::runtime_error(msg.str());
77   }
78 }
79
80 void
81 Addon::parse(std::string fname)
82 {
83   try {
84     lisp::Parser parser;
85     const lisp::Lisp* root = parser.parse(fname);
86     const lisp::Lisp* addon = root->get_lisp("supertux-addoninfo");
87     if(!addon) throw std::runtime_error("file is not a supertux-addoninfo file.");
88     parse(*addon);
89   } catch(std::exception& e) {
90     std::stringstream msg;
91     msg << "Problem when reading addoninfo '" << fname << "': " << e.what();
92     throw std::runtime_error(msg.str());
93   }
94 }
95
96 void
97 Addon::write(lisp::Writer& writer) const
98 {
99   writer.start_list("supertux-addoninfo");
100   if (kind != "") writer.write("kind", kind);  
101   if (title != "") writer.write("title", title);
102   if (author != "") writer.write("author", author);
103   if (license != "") writer.write("license", license);
104   if (http_url != "") writer.write("http-url", http_url);
105   if (suggested_filename != "") writer.write("file", suggested_filename);
106   if (stored_md5 != "") writer.write("md5", stored_md5);
107   writer.end_list("supertux-addoninfo");
108 }
109
110 void 
111 Addon::write(std::string fname) const
112 {
113   lisp::Writer writer(fname);
114   write(writer);
115 }
116
117 bool 
118 Addon::operator==(Addon addon2) const
119 {
120   std::string s1 = this->get_md5();
121   std::string s2 = addon2.get_md5();
122
123   if ((s1 != "") && (s2 != "")) return (s1 == s2);
124
125   if (this->title != addon2.title) return false;
126   if (this->author != addon2.author) return false;
127   if (this->kind != addon2.kind) return false;
128   return true; 
129 }
130
131 /* EOF */