Fix T51292: Alembic import, show notification when trying to load HDF5

HDF5 Alembic files are not officially supported by Blender. With this
commit, the HDF5 format is detected even when Blender is compiled without
HDF5 support, and the user is given an explanatory error message (rather
than the generic "Could not open Alembic archive for reading".
This commit is contained in:
Sybren A. Stüvel 2017-04-25 14:30:01 +02:00
parent ab4f6f01a6
commit 9dadd5ff93
3 changed files with 50 additions and 5 deletions

@ -28,6 +28,8 @@
# include "utfconv.h" # include "utfconv.h"
#endif #endif
#include <fstream>
using Alembic::Abc::Exception; using Alembic::Abc::Exception;
using Alembic::Abc::ErrorHandler; using Alembic::Abc::ErrorHandler;
using Alembic::Abc::IArchive; using Alembic::Abc::IArchive;
@ -38,8 +40,9 @@ static IArchive open_archive(const std::string &filename,
const std::vector<std::istream *> &input_streams, const std::vector<std::istream *> &input_streams,
bool &is_hdf5) bool &is_hdf5)
{ {
try {
is_hdf5 = false; is_hdf5 = false;
try {
Alembic::AbcCoreOgawa::ReadArchive archive_reader(input_streams); Alembic::AbcCoreOgawa::ReadArchive archive_reader(input_streams);
return IArchive(archive_reader(filename), return IArchive(archive_reader(filename),
@ -63,6 +66,27 @@ static IArchive open_archive(const std::string &filename,
return IArchive(); return IArchive();
} }
#else #else
/* Inspect the file to see whether it's really a HDF5 file. */
char header[4]; /* char(0x89) + "HDF" */
std::ifstream the_file(filename, std::ios::in | std::ios::binary);
if (!the_file) {
std::cerr << "Unable to open " << filename << std::endl;
}
else if (!the_file.read(header, sizeof(header))) {
std::cerr << "Unable to read from " << filename << std::endl;
}
else if (strncmp(header + 1, "HDF", 3)) {
std::cerr << filename << " has an unknown file format, unable to read." << std::endl;
}
else {
is_hdf5 = true;
std::cerr << filename << " is in the obsolete HDF5 format, unable to read." << std::endl;
}
if (the_file.is_open()) {
the_file.close();
}
return IArchive(); return IArchive();
#endif #endif
} }
@ -83,16 +107,20 @@ ArchiveReader::ArchiveReader(const char *filename)
m_streams.push_back(&m_infile); m_streams.push_back(&m_infile);
bool is_hdf5; m_archive = open_archive(filename, m_streams, m_is_hdf5);
m_archive = open_archive(filename, m_streams, is_hdf5);
/* We can't open an HDF5 file from a stream, so close it. */ /* We can't open an HDF5 file from a stream, so close it. */
if (is_hdf5) { if (m_is_hdf5) {
m_infile.close(); m_infile.close();
m_streams.clear(); m_streams.clear();
} }
} }
bool ArchiveReader::is_hdf5() const
{
return m_is_hdf5;
}
bool ArchiveReader::valid() const bool ArchiveReader::valid() const
{ {
return m_archive.valid(); return m_archive.valid();

@ -44,12 +44,21 @@ class ArchiveReader {
Alembic::Abc::IArchive m_archive; Alembic::Abc::IArchive m_archive;
std::ifstream m_infile; std::ifstream m_infile;
std::vector<std::istream *> m_streams; std::vector<std::istream *> m_streams;
bool m_is_hdf5;
public: public:
explicit ArchiveReader(const char *filename); explicit ArchiveReader(const char *filename);
bool valid() const; bool valid() const;
/**
* Returns true when either Blender is compiled with HDF5 support and
* the archive was succesfully opened (valid() will also return true),
* or when Blender was built without HDF5 support but a HDF5 file was
* detected (valid() will return false).
*/
bool is_hdf5() const;
Alembic::Abc::IObject getTop(); Alembic::Abc::IObject getTop();
}; };

@ -595,6 +595,7 @@ static std::pair<bool, AbcObjectReader *> visit_object(
enum { enum {
ABC_NO_ERROR = 0, ABC_NO_ERROR = 0,
ABC_ARCHIVE_FAIL, ABC_ARCHIVE_FAIL,
ABC_UNSUPPORTED_HDF5,
}; };
struct ImportJobData { struct ImportJobData {
@ -659,8 +660,12 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
ArchiveReader *archive = new ArchiveReader(data->filename); ArchiveReader *archive = new ArchiveReader(data->filename);
if (!archive->valid()) { if (!archive->valid()) {
delete archive; #ifndef WITH_ALEMBIC_HDF5
data->error_code = archive->is_hdf5() ? ABC_UNSUPPORTED_HDF5 : ABC_ARCHIVE_FAIL;
#else
data->error_code = ABC_ARCHIVE_FAIL; data->error_code = ABC_ARCHIVE_FAIL;
#endif
delete archive;
return; return;
} }
@ -829,6 +834,9 @@ static void import_endjob(void *user_data)
case ABC_ARCHIVE_FAIL: case ABC_ARCHIVE_FAIL:
WM_report(RPT_ERROR, "Could not open Alembic archive for reading! See console for detail."); WM_report(RPT_ERROR, "Could not open Alembic archive for reading! See console for detail.");
break; break;
case ABC_UNSUPPORTED_HDF5:
WM_report(RPT_ERROR, "Alembic archive in obsolete HDF5 format is not supported.");
break;
} }
WM_main_add_notifier(NC_SCENE | ND_FRAME, data->scene); WM_main_add_notifier(NC_SCENE | ND_FRAME, data->scene);