Browse Source

[godot] Related to #2134, validate .json and .skel files before import.

Mario Zechner 3 years ago
parent
commit
db03f8612d

+ 6 - 4
spine-godot/spine_godot/SpineEditorPlugin.cpp

@@ -71,11 +71,12 @@ Error SpineJsonResourceImportPlugin::import(const String &source_file, const Str
 Error SpineJsonResourceImportPlugin::import(const String &source_file, const String &save_path, const Map<StringName, Variant> &options, List<String> *platform_variants, List<String> *gen_files, Variant *metadata) {
 #endif
 	Ref<SpineSkeletonFileResource> skeleton_file_res(memnew(SpineSkeletonFileResource));
-	skeleton_file_res->load_from_file(source_file);
+        Error error = skeleton_file_res->load_from_file(source_file);
+        if (error != OK) return error;
 
 	String file_name = vformat("%s.%s", save_path, get_save_extension());
 #if VERSION_MAJOR > 3
-	auto error = ResourceSaver::save(skeleton_file_res, file_name);
+	error = ResourceSaver::save(skeleton_file_res, file_name);
 #else
 	auto error = ResourceSaver::save(file_name, skeleton_file_res);
 #endif
@@ -88,11 +89,12 @@ Error SpineBinaryResourceImportPlugin::import(const String &source_file, const S
 Error SpineBinaryResourceImportPlugin::import(const String &source_file, const String &save_path, const Map<StringName, Variant> &options, List<String> *platform_variants, List<String> *gen_files, Variant *metadata) {
 #endif
 	Ref<SpineSkeletonFileResource> skeleton_file_res(memnew(SpineSkeletonFileResource));
-	skeleton_file_res->load_from_file(source_file);
+	Error error = skeleton_file_res->load_from_file(source_file);
+        if (error != OK) return error;
 
 	String file_name = vformat("%s.%s", save_path, get_save_extension());
 #if VERSION_MAJOR > 3
-	auto error = ResourceSaver::save(skeleton_file_res, file_name);
+	error = ResourceSaver::save(skeleton_file_res, file_name);
 #else
 	auto error = ResourceSaver::save(file_name, skeleton_file_res);
 #endif

+ 6 - 0
spine-godot/spine_godot/SpineEditorPlugin.h

@@ -57,6 +57,8 @@ public:
 #if VERSION_MAJOR > 3
 	int get_import_order() const override { return IMPORT_ORDER_DEFAULT; }
 
+        float get_priority() const override { return 1; }
+
 	void get_import_options(const String &path, List<ImportOption> *options, int preset) const override;
 
 	virtual bool get_option_visibility(const String &path, const String &option, const HashMap<StringName, Variant> &options) const override { return true; }
@@ -92,6 +94,8 @@ public:
 #if VERSION_MAJOR > 3
 	int get_import_order() const override { return IMPORT_ORDER_DEFAULT; }
 
+        float get_priority() const override { return 1; }
+
 	void get_import_options(const String &path, List<ImportOption> *options, int preset) const override {}
 
 	bool get_option_visibility(const String &path, const String &option, const HashMap<StringName, Variant> &options) const override { return true; }
@@ -127,6 +131,8 @@ public:
 #if VERSION_MAJOR > 3
 	int get_import_order() const override { return IMPORT_ORDER_DEFAULT; }
 
+        float get_priority() const override { return 1; }
+
 	void get_import_options(const String &path, List<ImportOption> *options, int preset) const override {}
 
 	bool get_option_visibility(const String &path, const String &option, const HashMap<StringName, Variant> &options) const override { return true; }

+ 88 - 5
spine-godot/spine_godot/SpineSkeletonFileResource.cpp

@@ -33,16 +33,99 @@
 #else
 #include "core/os/file_access.h"
 #endif
+#include <spine/Json.h>
+#include <spine/Version.h>
+#include <spine/Extension.h>
+
+
+struct BinaryInput {
+  const unsigned char *cursor;
+  const unsigned char *end;
+};
+
+static unsigned char readByte(BinaryInput *input) {
+  return *input->cursor++;
+}
+
+static int readVarint(BinaryInput *input, bool optimizePositive) {
+  unsigned char b = readByte(input);
+  int value = b & 0x7F;
+  if (b & 0x80) {
+    b = readByte(input);
+    value |= (b & 0x7F) << 7;
+    if (b & 0x80) {
+      b = readByte(input);
+      value |= (b & 0x7F) << 14;
+      if (b & 0x80) {
+        b = readByte(input);
+        value |= (b & 0x7F) << 21;
+        if (b & 0x80) value |= (readByte(input) & 0x7F) << 28;
+      }
+    }
+  }
+
+  if (!optimizePositive) {
+    value = (((unsigned int) value >> 1) ^ -(value & 1));
+  }
+
+  return value;
+}
+
+static char *readString(BinaryInput *input) {
+  int length = readVarint(input, true);
+  char *string;
+  if (length == 0) {
+    return NULL;
+  }
+  string = spine::SpineExtension::alloc<char>(length, __FILE__, __LINE__);
+  memcpy(string, input->cursor, length - 1);
+  input->cursor += length - 1;
+  string[length - 1] = '\0';
+  return string;
+}
 
 void SpineSkeletonFileResource::_bind_methods() {
 }
 
+static bool checkVersion(const char *version) {
+  if (!version) return false;
+  char *result = (char *) (strstr(version, SPINE_VERSION_STRING) - version);
+  return result == 0;
+}
+
+static bool checkJson(const char *jsonData) {
+  spine::Json json(jsonData);
+  spine::Json *skeleton = spine::Json::getItem(&json, "skeleton");
+  if (!skeleton) return false;
+  const char *version = spine::Json::getString(skeleton, "spine", 0);
+  if (!version) return false;
+
+  return checkVersion(version);
+}
+
+static bool checkBinary(const char *binaryData, int length) {
+  BinaryInput input;
+  input.cursor = (const unsigned char *) binaryData;
+  input.end = (const unsigned char *) binaryData + length;
+  // Skip hash
+  input.cursor += 8;
+  char *version = readString(&input);
+  bool result = checkVersion(version);
+  spine::SpineExtension::free(version, __FILE__, __LINE__);
+  return result;
+}
+
 Error SpineSkeletonFileResource::load_from_file(const String &path) {
-	Error error;
-	if (path.ends_with("spjson"))
-		json = FileAccess::get_file_as_string(path, &error);
-	else
-		binary = FileAccess::get_file_as_array(path, &error);
+	Error error = OK;
+	if (path.ends_with(".spjson") || path.ends_with(".json")) {
+          json = FileAccess::get_file_as_string(path, &error);
+          if (error != OK) return error;
+          if (!checkJson(json.utf8())) return ERR_INVALID_DATA;
+        } else {
+          binary = FileAccess::get_file_as_array(path, &error);
+          if (error != OK) return error;
+          if (!checkBinary((const char*)binary.ptr(), binary.size())) return ERR_INVALID_DATA;
+        }
 	return error;
 }