mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-11 13:17:00 -04:00
The 'Big Whine' patch:
Any use of a file from another package without a declared dependency will give a warning; Also added some more _LOCALE_123_ macros so we need less format_string calls git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@753 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
+27
-3
@@ -178,10 +178,15 @@ class BufferedFileInputStream : private BufferedFileInputStream_aux, public wxBu
|
||||
InputStreamP Package::openIn(const String& file) {
|
||||
if (!file.empty() && file.GetChar(0) == _('/')) {
|
||||
// absolute path, open file from another package
|
||||
return packages.openFileFromPackage(file);
|
||||
Packaged* p = dynamic_cast<Packaged*>(this);
|
||||
return packages.openFileFromPackage(p, file);
|
||||
}
|
||||
FileInfos::iterator it = files.find(toStandardName(file));
|
||||
if (it == files.end()) {
|
||||
// does it look like a relative filename?
|
||||
if (filename.find(_(".mse-")) != String::npos) {
|
||||
throw PackageError(_ERROR_2_("file not found package like", file, filename));
|
||||
}
|
||||
throw FileNotFoundError(file, filename);
|
||||
}
|
||||
InputStreamP stream;
|
||||
@@ -442,6 +447,7 @@ IMPLEMENT_REFLECTION(Packaged) {
|
||||
REFLECT_N("icon", icon_filename);
|
||||
REFLECT_NO_SCRIPT(position_hint);
|
||||
REFLECT(version);
|
||||
REFLECT(compatible_version);
|
||||
REFLECT_NO_SCRIPT_N("depends ons", dependencies); // hack for singular_form
|
||||
}
|
||||
|
||||
@@ -472,7 +478,7 @@ void Packaged::open(const String& package, bool just_header) {
|
||||
fully_loaded = false;
|
||||
if (just_header) {
|
||||
// Read just the header (the part common to all Packageds)
|
||||
Reader reader(openIn(typeName()), absoluteFilename() + _("/") + typeName(), true);
|
||||
Reader reader(openIn(typeName()), this, absoluteFilename() + _("/") + typeName(), true);
|
||||
try {
|
||||
JustAsPackageProxy proxy(this);
|
||||
reader.handle_greedy(proxy);
|
||||
@@ -487,7 +493,7 @@ void Packaged::open(const String& package, bool just_header) {
|
||||
void Packaged::loadFully() {
|
||||
if (fully_loaded) return;
|
||||
fully_loaded = true;
|
||||
Reader reader(openIn(typeName()), absoluteFilename() + _("/") + typeName());
|
||||
Reader reader(openIn(typeName()), this, absoluteFilename() + _("/") + typeName());
|
||||
try {
|
||||
reader.handle_greedy(*this);
|
||||
validate(reader.file_app_version);
|
||||
@@ -518,6 +524,24 @@ void Packaged::validate(Version) {
|
||||
}
|
||||
}
|
||||
|
||||
void Packaged::requireDependency(Packaged* package) {
|
||||
if (package == this) return; // dependency on self
|
||||
String n = package->relativeFilename();
|
||||
FOR_EACH(dep, dependencies) {
|
||||
if (dep->package == n) {
|
||||
if (package->version < dep->version) {
|
||||
handle_warning(_ERROR_3_("package out of date", n, package->version.toString(), dep->version.toString()), false);
|
||||
} else if (package->compatible_version > dep->version) {
|
||||
handle_warning(_ERROR_4_("package too new", n, package->version.toString(), dep->version.toString(), relativeFilename()), false);
|
||||
} else {
|
||||
return; // ok
|
||||
}
|
||||
}
|
||||
}
|
||||
// dependency not found
|
||||
handle_warning(_ERROR_4_("dependency not given", name(), package->relativeFilename(), package->relativeFilename(), package->version.toString()), false);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : IncludePackage
|
||||
|
||||
String IncludePackage::typeName() const { return _("include"); }
|
||||
|
||||
+11
-6
@@ -117,7 +117,7 @@ class Package : public IntrusivePtrVirtualBase {
|
||||
|
||||
template <typename T>
|
||||
void readFile(const String& file, T& obj) {
|
||||
Reader reader(openIn(file), absoluteFilename() + _("/") + file);
|
||||
Reader reader(openIn(file), dynamic_cast<Packaged*>(this), absoluteFilename() + _("/") + file);
|
||||
try {
|
||||
reader.handle_greedy(obj);
|
||||
} catch (const ParseError& err) {
|
||||
@@ -196,12 +196,13 @@ class Packaged : public Package {
|
||||
Packaged();
|
||||
virtual ~Packaged() {}
|
||||
|
||||
Version version; ///< Version number of this package
|
||||
String short_name; ///< Short name of this package
|
||||
String full_name; ///< Name of this package, for menus etc.
|
||||
String icon_filename; ///< Filename of icon to use in package lists
|
||||
Version version; ///< Version number of this package
|
||||
Version compatible_version; ///< Earliest version number this package is compatible with
|
||||
String short_name; ///< Short name of this package
|
||||
String full_name; ///< Name of this package, for menus etc.
|
||||
String icon_filename; ///< Filename of icon to use in package lists
|
||||
vector<PackageDependencyP> dependencies; ///< Dependencies of this package
|
||||
int position_hint; ///< A hint for the package list
|
||||
int position_hint; ///< A hint for the package list
|
||||
|
||||
/// Get an input stream for the package icon, if there is any
|
||||
InputStreamP openIconFile();
|
||||
@@ -215,6 +216,10 @@ class Packaged : public Package {
|
||||
void save();
|
||||
void saveAs(const String& package, bool remove_unused = true);
|
||||
|
||||
/// Check if this package lists a dependency on the given package
|
||||
/** This is done to force people to fill in the dependencies */
|
||||
void requireDependency(Packaged* package);
|
||||
|
||||
protected:
|
||||
/// filename of the data file, and extension of the package file
|
||||
virtual String typeName() const = 0;
|
||||
|
||||
@@ -101,17 +101,24 @@ void PackageManager::findMatching(const String& pattern, vector<PackagedP>& out)
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
InputStreamP PackageManager::openFileFromPackage(Packaged*& package, const String& name) {
|
||||
if (!name.empty() && name.GetChar(0) == _('/')) {
|
||||
// absolute name; break name
|
||||
size_t pos = name.find_first_of(_("/\\"), 1);
|
||||
if (pos != String::npos) {
|
||||
// open package
|
||||
PackagedP p = openAny(name.substr(1, pos-1));
|
||||
if (package) {
|
||||
package->requireDependency(p.get());
|
||||
}
|
||||
package = p.get();
|
||||
return p->openIn(name.substr(pos + 1));
|
||||
}
|
||||
} else if (package) {
|
||||
// relative name
|
||||
return package->openIn(name);
|
||||
}
|
||||
throw FileNotFoundError(name, _("No package name specified, use '/package/filename'"));
|
||||
}
|
||||
|
||||
bool PackageManager::checkDependency(const PackageDependency& dep, bool report_errors) {
|
||||
|
||||
@@ -66,12 +66,18 @@ class PackageManager {
|
||||
/** Only reads the package headers */
|
||||
void findMatching(const String& pattern, vector<PackagedP>& out);
|
||||
|
||||
/// Open a file from a package, with a name encoded as "package/file"
|
||||
InputStreamP openFileFromPackage(const String& name);
|
||||
/// Open a file from a package, with a name encoded as "/package/file"
|
||||
/** If 'package' is set then:
|
||||
* - tries to open a relative file from the package if the name is "file"
|
||||
* - verifies a dependency from that package if an absolute filename is used
|
||||
* this is to force people to fill in the dependencies
|
||||
* Afterwards, package will be set to the package the file is opened from
|
||||
*/
|
||||
InputStreamP openFileFromPackage(Packaged*& package, const String& name);
|
||||
|
||||
/// Check if the given dependency is currently installed
|
||||
bool checkDependency(const PackageDependency& dep, bool report_errors = false);
|
||||
|
||||
bool checkDependency(const PackageDependency& dep, bool report_errors = true);
|
||||
|
||||
inline String getGlobalDataDir() const { return global_data_directory; }
|
||||
inline String getLocalDataDir() const { return local_data_directory; }
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
|
||||
// ----------------------------------------------------------------------------- : Reader
|
||||
|
||||
Reader::Reader(const InputStreamP& input, const String& filename, bool ignore_invalid)
|
||||
Reader::Reader(const InputStreamP& input, Packaged* package, const String& filename, bool ignore_invalid)
|
||||
: indent(0), expected_indent(0), state(OUTSIDE)
|
||||
, filename(filename), line_number(0), previous_line_number(0)
|
||||
, package(package), filename(filename), line_number(0), previous_line_number(0)
|
||||
, ignore_invalid(ignore_invalid)
|
||||
, input(input)
|
||||
{
|
||||
@@ -24,12 +24,12 @@ Reader::Reader(const InputStreamP& input, const String& filename, bool ignore_in
|
||||
handleAppVersion();
|
||||
}
|
||||
|
||||
Reader::Reader(const String& filename)
|
||||
Reader::Reader(Packaged* pkg, const String& filename)
|
||||
: indent(0), expected_indent(0), state(OUTSIDE)
|
||||
, filename(filename), line_number(0), previous_line_number(0)
|
||||
, package(pkg), filename(filename), line_number(0), previous_line_number(0)
|
||||
, ignore_invalid(false)
|
||||
, input(packages.openFileFromPackage(filename))
|
||||
{
|
||||
input = packages.openFileFromPackage(package, filename);
|
||||
moveNext();
|
||||
handleAppVersion();
|
||||
}
|
||||
|
||||
+12
-4
@@ -16,6 +16,7 @@ template <typename T> class Defaultable;
|
||||
template <typename T> class Scriptable;
|
||||
DECLARE_POINTER_TYPE(Game);
|
||||
DECLARE_POINTER_TYPE(StyleSheet);
|
||||
class Packaged;
|
||||
|
||||
// ----------------------------------------------------------------------------- : Reader
|
||||
|
||||
@@ -35,11 +36,13 @@ class Reader {
|
||||
/// Construct a reader that reads from the given input stream
|
||||
/** filename is used only for error messages
|
||||
*/
|
||||
Reader(const InputStreamP& input, const String& filename = wxEmptyString, bool ignore_invalid = false);
|
||||
Reader(const InputStreamP& input, Packaged* package = nullptr, const String& filename = wxEmptyString, bool ignore_invalid = false);
|
||||
|
||||
/// Construct a reader that reads a file in a package
|
||||
/** Used for "include file" keys. */
|
||||
Reader(const String& filename);
|
||||
/** Used for "include file" keys.
|
||||
* package can be nullptr
|
||||
*/
|
||||
Reader(Packaged* package, const String& filename);
|
||||
|
||||
~Reader() { showWarnings(); }
|
||||
|
||||
@@ -108,6 +111,9 @@ class Reader {
|
||||
/// Indicate that the last value from getValue() was not handled, allowing it to be handled again
|
||||
void unhandle();
|
||||
|
||||
/// The package being read from
|
||||
inline Packaged* getPackage() const { return package; }
|
||||
|
||||
// --------------------------------------------------- : Data
|
||||
/// App version this file was made with
|
||||
Version file_app_version;
|
||||
@@ -141,6 +147,8 @@ class Reader {
|
||||
|
||||
/// Filename for error messages
|
||||
String filename;
|
||||
/// Package this file is from, if any
|
||||
Packaged* package;
|
||||
/// Line number of the current line for error messages
|
||||
int line_number;
|
||||
/// Line number of the previous_line
|
||||
@@ -172,7 +180,7 @@ class Reader {
|
||||
template <typename T>
|
||||
void unknownKey(T& v) {
|
||||
if (key == _("include file")) {
|
||||
Reader reader(value);
|
||||
Reader reader(package, value);
|
||||
reader.handle_greedy(v);
|
||||
moveNext();
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user