diff --git a/src/util/io/package_manager.cpp b/src/util/io/package_manager.cpp index dffe4baa..ac7ec4a1 100644 --- a/src/util/io/package_manager.cpp +++ b/src/util/io/package_manager.cpp @@ -10,6 +10,26 @@ #include #include +// ----------------------------------------------------------------------------- : IncludePackage + +/// A package that just contains a bunch of files that are used from other packages +class IncludePackage : public Packaged { + protected: + String typeName() const; + DECLARE_REFLECTION(); +}; + +String IncludePackage::typeName() const { return _("include"); } + +IMPLEMENT_REFLECTION(IncludePackage) { + if (tag.reading()) { + // ingore + String full_name, version; + REFLECT(full_name); + REFLECT(version); + } +} + // ----------------------------------------------------------------------------- : PackageManager String program_dir() { @@ -50,10 +70,10 @@ PackagedP PackageManager::openAny(const String& name) { if (fn.GetExt() == _("mse-game")) p = new_shared(); // else if (fn.GetExt() == _("mse-style")) p = new_shared(); // else if (fn.GetExt() == _("mse-locale")) p = new_shared(); -// else if (fn.GetExt() == _("mse-include")) p = new_shared(); + else if (fn.GetExt() == _("mse-include")) p = new_shared(); // else if (fn.GetExt() == _("mse-symbol-font")) p = new_shared(); else { - throw PackageError(_("Unrecognized package type: ") + fn.GetExt()); + throw PackageError(_("Unrecognized package type: '") + fn.GetExt() + _("'\nwhile trying to open: ") + name); } p->open(filename); return p; @@ -64,6 +84,19 @@ String PackageManager::findFirst(const String& pattern) { return wxFindFirstFile(data_directory + _("/") + pattern, 0); } +InputStreamP PackageManager::openFileFromPackage(const String& name) { + // we don't want an absolute path (for security reasons) + String n; + if (!name.empty() && name.GetChar(0) == _('/')) n = name.substr(1); + else n = name; + // break + size_t pos = n.find_first_of(_("/\\")); + if (pos == String::npos) throw FileNotFoundError(n, _("No package name specified, use 'package/filename'")); + // open package and file + PackagedP p = openAny(n.substr(0, pos)); + return p->openIn(n.substr(pos+1)); +} + void PackageManager::destroy() { loaded_packages.clear(); } \ No newline at end of file diff --git a/src/util/io/package_manager.hpp b/src/util/io/package_manager.hpp index 8c5d97f3..0df68399 100644 --- a/src/util/io/package_manager.hpp +++ b/src/util/io/package_manager.hpp @@ -53,6 +53,9 @@ class PackageManager { */ String findFirst(const String& pattern); + // Open a file from a package, with a name encoded as "package/file" + InputStreamP openFileFromPackage(const String& name); + /// Empty the list of packages. /** This function MUST be called before the program terminates, otherwise * we could get into fights with pool allocators used by ScriptValues */ diff --git a/src/util/io/reader.cpp b/src/util/io/reader.cpp index ac39fe1c..56a4743a 100644 --- a/src/util/io/reader.cpp +++ b/src/util/io/reader.cpp @@ -9,10 +9,11 @@ #include "reader.hpp" #include #include +#include // ----------------------------------------------------------------------------- : Reader -Reader::Reader(const InputStreamP& input, String filename) +Reader::Reader(const InputStreamP& input, const String& filename) : input(input), filename(filename), line_number(0) , indent(0), expected_indent(0), just_opened(false) , stream(*input) @@ -20,6 +21,16 @@ Reader::Reader(const InputStreamP& input, String filename) moveNext(); } +Reader::Reader(const String& filename) + : input(packages.openFileFromPackage(filename)) + , filename(filename), line_number(0) + , indent(0), expected_indent(0), just_opened(false) + , stream(*input) +{ + moveNext(); +} + + void Reader::warning(const String& msg) { wxMessageBox((msg + _("\nOn line: ")) << line_number << _("\nIn file: ") << filename, _("Warning"), wxOK | wxICON_EXCLAMATION); } @@ -84,6 +95,13 @@ void Reader::readLine() { value = pos == String::npos ? _("") : trim_left(line.substr(pos+1)); } +void Reader::unknownKey() { + warning(_("Unexpected key: '") + key + _("'")); + do { + moveNext(); + } while (indent > expected_indent); +} + // ----------------------------------------------------------------------------- : Handling basic types template <> void Reader::handle(String& s) { diff --git a/src/util/io/reader.hpp b/src/util/io/reader.hpp index b7e12d51..8ffd4cca 100644 --- a/src/util/io/reader.hpp +++ b/src/util/io/reader.hpp @@ -33,10 +33,11 @@ class Reader { /// Construct a reader that reads from the given input stream /** filename is used only for error messages */ - Reader(const InputStreamP& input, String filename = _("")); + Reader(const InputStreamP& input, const String& filename = wxEmptyString); /// Construct a reader that reads a file in a package - Reader(String filename); + /** Used for "include file" keys. */ + Reader(const String& filename); /// Tell the reflection code we are reading inline bool reading() const { return true; } @@ -106,8 +107,18 @@ class Reader { /// Reads the next line from the input, and stores it in line/key/value/indent void readLine(); - /// Issue a warning: "Unexpected key: $key" - void unexpected(); + /// No line was read, because nothing mathes the current key + /** Maybe the key is "include file" */ + template + void unknownKey(T& v) { + if (key == _("include_file")) { + Reader reader(value); + reader.handle(v); + } else { + unknownKey(); + } + } + void unknownKey(); }; // ----------------------------------------------------------------------------- : Container types @@ -150,13 +161,7 @@ void Reader::handle(map& map) { while (indent >= expected_indent) { \ UInt l = line_number; \ object.reflect(*this); \ - if (l == line_number) { \ - /* warning: unexpected key */ \ - warning(_("Unexpected key: '") + key + _("'")); \ - do { \ - moveNext(); \ - } while (indent > expected_indent); \ - } \ + if (l == line_number) unknownKey(object); \ } \ } \ void Cls::reflect(Reader& reader) { \