Fix: Proper error handling for STL, PLY, and OBJ IO
Properly handle exceptions from STL and PLY code to prevent crashes on invalid file paths. This will now also Report errors/warnings to the callers of these formats as well. For the UI this means a Report banner and Info editor entry. For Python scripts this means an exception instead of silently continuing. Related to #117881 Pull Request: https://projects.blender.org/blender/blender/pulls/118731
This commit is contained in:
committed by
Jesse Yurkovich
parent
3748e49034
commit
5d9e127234
@@ -106,6 +106,8 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
|
||||
export_params.export_smooth_groups = RNA_boolean_get(op->ptr, "export_smooth_groups");
|
||||
export_params.smooth_groups_bitflags = RNA_boolean_get(op->ptr, "smooth_group_bitflags");
|
||||
|
||||
export_params.reports = op->reports;
|
||||
|
||||
OBJ_export(C, &export_params);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -404,6 +406,8 @@ static int wm_obj_import_exec(bContext *C, wmOperator *op)
|
||||
import_params.relative_paths = ((U.flag & USER_RELPATHS) != 0);
|
||||
import_params.clear_selection = true;
|
||||
|
||||
import_params.reports = op->reports;
|
||||
|
||||
const auto paths = blender::ed::io::paths_from_operator_properties(op->ptr);
|
||||
|
||||
if (paths.is_empty()) {
|
||||
|
||||
@@ -70,7 +70,7 @@ static int wm_ply_export_exec(bContext *C, wmOperator *op)
|
||||
BKE_report(op->reports, RPT_ERROR, "No filepath given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
PLYExportParams export_params = {"\0"};
|
||||
PLYExportParams export_params{};
|
||||
export_params.file_base_for_tests[0] = '\0';
|
||||
RNA_string_get(op->ptr, "filepath", export_params.filepath);
|
||||
export_params.blen_filepath = CTX_data_main(C)->filepath;
|
||||
@@ -88,6 +88,8 @@ static int wm_ply_export_exec(bContext *C, wmOperator *op)
|
||||
export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh");
|
||||
export_params.ascii_format = RNA_boolean_get(op->ptr, "ascii_format");
|
||||
|
||||
export_params.reports = op->reports;
|
||||
|
||||
PLY_export(C, &export_params);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -251,6 +253,8 @@ static int wm_ply_import_exec(bContext *C, wmOperator *op)
|
||||
params.import_attributes = RNA_boolean_get(op->ptr, "import_attributes");
|
||||
params.vertex_colors = ePLYVertexColorMode(RNA_enum_get(op->ptr, "import_colors"));
|
||||
|
||||
params.reports = op->reports;
|
||||
|
||||
const auto paths = blender::ed::io::paths_from_operator_properties(op->ptr);
|
||||
|
||||
if (paths.is_empty()) {
|
||||
@@ -259,7 +263,7 @@ static int wm_ply_import_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
for (const auto &path : paths) {
|
||||
STRNCPY(params.filepath, path.c_str());
|
||||
PLY_import(C, ¶ms, op);
|
||||
PLY_import(C, ¶ms);
|
||||
};
|
||||
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
@@ -48,7 +48,7 @@ static int wm_stl_export_execute(bContext *C, wmOperator *op)
|
||||
BKE_report(op->reports, RPT_ERROR, "No filename given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
STLExportParams export_params;
|
||||
STLExportParams export_params{};
|
||||
RNA_string_get(op->ptr, "filepath", export_params.filepath);
|
||||
export_params.forward_axis = eIOAxis(RNA_enum_get(op->ptr, "forward_axis"));
|
||||
export_params.up_axis = eIOAxis(RNA_enum_get(op->ptr, "up_axis"));
|
||||
@@ -59,6 +59,8 @@ static int wm_stl_export_execute(bContext *C, wmOperator *op)
|
||||
export_params.ascii_format = RNA_boolean_get(op->ptr, "ascii_format");
|
||||
export_params.use_batch = RNA_boolean_get(op->ptr, "use_batch");
|
||||
|
||||
export_params.reports = op->reports;
|
||||
|
||||
STL_export(C, &export_params);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -189,6 +191,8 @@ static int wm_stl_import_exec(bContext *C, wmOperator *op)
|
||||
params.global_scale = RNA_float_get(op->ptr, "global_scale");
|
||||
params.use_mesh_validate = RNA_boolean_get(op->ptr, "use_mesh_validate");
|
||||
|
||||
params.reports = op->reports;
|
||||
|
||||
const auto paths = blender::ed::io::paths_from_operator_properties(op->ptr);
|
||||
|
||||
if (paths.is_empty()) {
|
||||
|
||||
@@ -32,9 +32,9 @@ void PLY_export(bContext *C, const PLYExportParams *export_params)
|
||||
report_duration("export", start_time, export_params->filepath);
|
||||
}
|
||||
|
||||
void PLY_import(bContext *C, const PLYImportParams *import_params, wmOperator *op)
|
||||
void PLY_import(bContext *C, const PLYImportParams *import_params)
|
||||
{
|
||||
TimePoint start_time = Clock::now();
|
||||
blender::io::ply::importer_main(C, *import_params, op);
|
||||
blender::io::ply::importer_main(C, *import_params);
|
||||
report_duration("import", start_time, import_params->filepath);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ struct PLYExportParams {
|
||||
ePLYVertexColorMode vertex_colors;
|
||||
bool export_attributes;
|
||||
bool export_triangulated_mesh;
|
||||
|
||||
ReportList *reports = nullptr;
|
||||
};
|
||||
|
||||
struct PLYImportParams {
|
||||
@@ -57,6 +59,8 @@ struct PLYImportParams {
|
||||
ePLYVertexColorMode vertex_colors;
|
||||
bool import_attributes;
|
||||
bool merge_verts;
|
||||
|
||||
ReportList *reports = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -64,4 +68,4 @@ struct PLYImportParams {
|
||||
*/
|
||||
void PLY_export(bContext *C, const PLYExportParams *export_params);
|
||||
|
||||
void PLY_import(bContext *C, const PLYImportParams *import_params, wmOperator *op);
|
||||
void PLY_import(bContext *C, const PLYImportParams *import_params);
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
* \ingroup ply
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "BKE_layer.hh"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "DNA_collection_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
@@ -32,11 +35,21 @@ void exporter_main(bContext *C, const PLYExportParams &export_params)
|
||||
|
||||
std::unique_ptr<FileBuffer> buffer;
|
||||
|
||||
if (export_params.ascii_format) {
|
||||
buffer = std::make_unique<FileBufferAscii>(export_params.filepath);
|
||||
try {
|
||||
if (export_params.ascii_format) {
|
||||
buffer = std::make_unique<FileBufferAscii>(export_params.filepath);
|
||||
}
|
||||
else {
|
||||
buffer = std::make_unique<FileBufferBinary>(export_params.filepath);
|
||||
}
|
||||
}
|
||||
else {
|
||||
buffer = std::make_unique<FileBufferBinary>(export_params.filepath);
|
||||
catch (const std::system_error &ex) {
|
||||
fprintf(stderr, "%s\n", ex.what());
|
||||
BKE_reportf(export_params.reports,
|
||||
RPT_ERROR,
|
||||
"PLY Export: Cannot open file '%s'",
|
||||
export_params.filepath);
|
||||
return;
|
||||
}
|
||||
|
||||
write_header(*buffer.get(), *plyData.get(), export_params);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* \ingroup ply
|
||||
*/
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_layer.hh"
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_mesh.hh"
|
||||
@@ -161,19 +162,18 @@ const char *read_header(PlyReadBuffer &file, PlyHeader &r_header)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void importer_main(bContext *C, const PLYImportParams &import_params, wmOperator *op)
|
||||
void importer_main(bContext *C, const PLYImportParams &import_params)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
importer_main(bmain, scene, view_layer, import_params, op);
|
||||
importer_main(bmain, scene, view_layer, import_params);
|
||||
}
|
||||
|
||||
void importer_main(Main *bmain,
|
||||
Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
const PLYImportParams &import_params,
|
||||
wmOperator *op)
|
||||
const PLYImportParams &import_params)
|
||||
{
|
||||
/* File base name used for both mesh and object. */
|
||||
char ob_name[FILE_MAX];
|
||||
@@ -187,7 +187,7 @@ void importer_main(Main *bmain,
|
||||
const char *err = read_header(file, header);
|
||||
if (err != nullptr) {
|
||||
fprintf(stderr, "PLY Importer: %s: %s\n", ob_name, err);
|
||||
BKE_reportf(op->reports, RPT_ERROR, "PLY Importer: %s: %s", ob_name, err);
|
||||
BKE_reportf(import_params.reports, RPT_ERROR, "PLY Importer: %s: %s", ob_name, err);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -195,17 +195,17 @@ void importer_main(Main *bmain,
|
||||
std::unique_ptr<PlyData> data = import_ply_data(file, header);
|
||||
if (data == nullptr) {
|
||||
fprintf(stderr, "PLY Importer: failed importing %s, unknown error\n", ob_name);
|
||||
BKE_report(op->reports, RPT_ERROR, "PLY Importer: failed importing, unknown error");
|
||||
BKE_report(import_params.reports, RPT_ERROR, "PLY Importer: failed importing, unknown error");
|
||||
return;
|
||||
}
|
||||
if (!data->error.empty()) {
|
||||
fprintf(stderr, "PLY Importer: failed importing %s: %s\n", ob_name, data->error.c_str());
|
||||
BKE_report(op->reports, RPT_ERROR, "PLY Importer: failed importing, unknown error");
|
||||
BKE_report(import_params.reports, RPT_ERROR, "PLY Importer: failed importing, unknown error");
|
||||
return;
|
||||
}
|
||||
if (data->vertices.is_empty()) {
|
||||
fprintf(stderr, "PLY Importer: file %s contains no vertices\n", ob_name);
|
||||
BKE_report(op->reports, RPT_ERROR, "PLY Importer: failed importing, no vertices");
|
||||
BKE_report(import_params.reports, RPT_ERROR, "PLY Importer: failed importing, no vertices");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,17 +15,14 @@ namespace blender::io::ply {
|
||||
|
||||
class PlyReadBuffer;
|
||||
|
||||
void splitstr(std::string str, Vector<std::string> &words, const StringRef &deli);
|
||||
|
||||
/* Main import function used from within Blender. */
|
||||
void importer_main(bContext *C, const PLYImportParams &import_params, wmOperator *op);
|
||||
void importer_main(bContext *C, const PLYImportParams &import_params);
|
||||
|
||||
/* Used from tests, where full bContext does not exist. */
|
||||
void importer_main(Main *bmain,
|
||||
Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
const PLYImportParams &import_params,
|
||||
wmOperator *op);
|
||||
const PLYImportParams &import_params);
|
||||
|
||||
const char *read_header(PlyReadBuffer &file, PlyHeader &r_header);
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ struct STLImportParams {
|
||||
bool use_scene_unit;
|
||||
float global_scale;
|
||||
bool use_mesh_validate;
|
||||
|
||||
ReportList *reports = nullptr;
|
||||
};
|
||||
|
||||
struct STLExportParams {
|
||||
@@ -34,6 +36,8 @@ struct STLExportParams {
|
||||
bool apply_modifiers;
|
||||
bool ascii_format;
|
||||
bool use_batch;
|
||||
|
||||
ReportList *reports = nullptr;
|
||||
};
|
||||
|
||||
void STL_import(bContext *C, const STLImportParams *import_params);
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_object.hh"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "BLI_string.h"
|
||||
|
||||
@@ -40,7 +42,17 @@ void export_frame(Depsgraph *depsgraph,
|
||||
|
||||
/* If not exporting in batch, create single writer for all objects. */
|
||||
if (!export_params.use_batch) {
|
||||
writer = std::make_unique<FileWriter>(export_params.filepath, export_params.ascii_format);
|
||||
try {
|
||||
writer = std::make_unique<FileWriter>(export_params.filepath, export_params.ascii_format);
|
||||
}
|
||||
catch (const std::runtime_error &ex) {
|
||||
fprintf(stderr, "%s\n", ex.what());
|
||||
BKE_reportf(export_params.reports,
|
||||
RPT_ERROR,
|
||||
"STL Export: Cannot open file '%s'",
|
||||
export_params.filepath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DEGObjectIterSettings deg_iter_settings{};
|
||||
@@ -70,7 +82,15 @@ void export_frame(Depsgraph *depsgraph,
|
||||
char filepath[FILE_MAX];
|
||||
STRNCPY(filepath, export_params.filepath);
|
||||
BLI_path_extension_replace(filepath, FILE_MAX, suffix.c_str());
|
||||
writer = std::make_unique<FileWriter>(filepath, export_params.ascii_format);
|
||||
try {
|
||||
writer = std::make_unique<FileWriter>(filepath, export_params.ascii_format);
|
||||
}
|
||||
catch (const std::runtime_error &ex) {
|
||||
fprintf(stderr, "%s\n", ex.what());
|
||||
BKE_reportf(
|
||||
export_params.reports, RPT_ERROR, "STL Export: Cannot open file '%s'", filepath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Object *obj_eval = DEG_get_evaluated_object(depsgraph, object);
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "BKE_customdata.hh"
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_layer.hh"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_object.hh"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "DNA_collection_types.h"
|
||||
#include "DNA_layer_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLI_fileops.hh"
|
||||
@@ -61,6 +63,10 @@ void importer_main(Main *bmain,
|
||||
FILE *file = BLI_fopen(import_params.filepath, "rb");
|
||||
if (!file) {
|
||||
fprintf(stderr, "Failed to open STL file:'%s'.\n", import_params.filepath);
|
||||
BKE_reportf(import_params.reports,
|
||||
RPT_ERROR,
|
||||
"STL Import: Cannot open file '%s'",
|
||||
import_params.filepath);
|
||||
return;
|
||||
}
|
||||
BLI_SCOPED_DEFER([&]() { fclose(file); });
|
||||
@@ -74,6 +80,10 @@ void importer_main(Main *bmain,
|
||||
fseek(file, BINARY_HEADER_SIZE, SEEK_SET);
|
||||
if (fread(&num_tri, sizeof(uint32_t), 1, file) != 1) {
|
||||
stl_import_report_error(file);
|
||||
BKE_reportf(import_params.reports,
|
||||
RPT_ERROR,
|
||||
"STL Import: Failed to read file '%s'",
|
||||
import_params.filepath);
|
||||
return;
|
||||
}
|
||||
bool is_ascii_stl = (file_size != (BINARY_HEADER_SIZE + 4 + BINARY_STRIDE * num_tri));
|
||||
@@ -89,6 +99,10 @@ void importer_main(Main *bmain,
|
||||
|
||||
if (mesh == nullptr) {
|
||||
fprintf(stderr, "STL Importer: Failed to import mesh '%s'\n", import_params.filepath);
|
||||
BKE_reportf(import_params.reports,
|
||||
RPT_ERROR,
|
||||
"STL Import: Failed to import mesh from file '%s'",
|
||||
import_params.filepath);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "IO_stl.hh"
|
||||
#include "stl_export.hh"
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@ struct OBJExportParams {
|
||||
bool export_smooth_groups;
|
||||
/* Create bitflags instead of the default "0"/"1" group IDs. */
|
||||
bool smooth_groups_bitflags;
|
||||
|
||||
ReportList *reports = nullptr;
|
||||
};
|
||||
|
||||
struct OBJImportParams {
|
||||
@@ -76,6 +78,8 @@ struct OBJImportParams {
|
||||
bool validate_meshes = false;
|
||||
bool relative_paths = true;
|
||||
bool clear_selection = true;
|
||||
|
||||
ReportList *reports = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <system_error>
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#include "BLI_path_util.h"
|
||||
@@ -259,6 +261,7 @@ void export_frame(Depsgraph *depsgraph, const OBJExportParams &export_params, co
|
||||
}
|
||||
catch (const std::system_error &ex) {
|
||||
print_exception_error(ex);
|
||||
BKE_reportf(export_params.reports, RPT_ERROR, "OBJ Export: Cannot open file '%s'", filepath);
|
||||
return;
|
||||
}
|
||||
if (!frame_writer) {
|
||||
@@ -272,6 +275,10 @@ void export_frame(Depsgraph *depsgraph, const OBJExportParams &export_params, co
|
||||
}
|
||||
catch (const std::system_error &ex) {
|
||||
print_exception_error(ex);
|
||||
BKE_reportf(export_params.reports,
|
||||
RPT_WARNING,
|
||||
"OBJ Export: Cannot create mtl file for '%s'",
|
||||
filepath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
* \ingroup obj
|
||||
*/
|
||||
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math_color.h"
|
||||
#include "BLI_math_vector.h"
|
||||
@@ -441,6 +443,10 @@ OBJParser::OBJParser(const OBJImportParams &import_params, size_t read_buffer_si
|
||||
obj_file_ = BLI_fopen(import_params_.filepath, "rb");
|
||||
if (!obj_file_) {
|
||||
fprintf(stderr, "Cannot read from OBJ file:'%s'.\n", import_params_.filepath);
|
||||
BKE_reportf(import_params_.reports,
|
||||
RPT_ERROR,
|
||||
"OBJ Import: Cannot open file '%s'",
|
||||
import_params_.filepath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_string_ref.hh"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_layer.hh"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@ struct OBJExportParamsDefault {
|
||||
params.export_vertex_groups = false;
|
||||
params.export_smooth_groups = true;
|
||||
params.smooth_groups_bitflags = false;
|
||||
|
||||
params.reports = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user