diff options
author | Kévin Dietrich <kevin.dietrich@mailoo.org> | 2016-08-25 06:19:41 +0300 |
---|---|---|
committer | Kévin Dietrich <kevin.dietrich@mailoo.org> | 2016-08-25 06:19:41 +0300 |
commit | 3c533be77ea8f6c88b188eb870bb46ba972d1372 (patch) | |
tree | 0cb7f2906d678e9f478ff16967afadda2ca21fcb /source/blender | |
parent | bfc5a94292bb6044e6f95d56d896ad2231e685e7 (diff) |
Fix T49112: Alembic unicode path issues on Windows.
Now we pass streams to Alembic instead of passing the filename string.
That way we can open the stream ourselves with the proper unicode
encoding.
Note that this only applies to Ogawa archive, as HDF5 does not support
streams.
Differential Revision: https://developer.blender.org/D2160
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/alembic/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/alembic/intern/abc_exporter.cc | 85 | ||||
-rw-r--r-- | source/blender/alembic/intern/abc_exporter.h | 2 | ||||
-rw-r--r-- | source/blender/alembic/intern/alembic_capi.cc | 125 |
4 files changed, 160 insertions, 53 deletions
diff --git a/source/blender/alembic/CMakeLists.txt b/source/blender/alembic/CMakeLists.txt index 42bd6a9c340..0b6b2433bd0 100644 --- a/source/blender/alembic/CMakeLists.txt +++ b/source/blender/alembic/CMakeLists.txt @@ -33,6 +33,7 @@ set(INC ../makesrna ../windowmanager ../../../intern/guardedalloc + ../../../intern/utfconv ) set(INC_SYS diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc index 2e9f429f887..764b1533309 100644 --- a/source/blender/alembic/intern/abc_exporter.cc +++ b/source/blender/alembic/intern/abc_exporter.cc @@ -30,6 +30,10 @@ #include <Alembic/AbcCoreOgawa/All.h> +#ifdef WIN32 +# include "utfconv.h" +#endif + #include "abc_camera.h" #include "abc_curves.h" #include "abc_hair.h" @@ -67,6 +71,54 @@ extern "C" { using Alembic::Abc::TimeSamplingPtr; using Alembic::Abc::OBox3dProperty; + +/* ************************************************************************** */ + +/* This kinda duplicates CreateArchiveWithInfo, but Alembic does not seem to + * have a version supporting streams. */ +static Alembic::Abc::OArchive create_archive(std::ostream *ostream, + const std::string &filename, + const std::string &scene_name, + const Alembic::Abc::Argument &arg0, + const Alembic::Abc::Argument &arg1, + bool ogawa) +{ + Alembic::Abc::MetaData md = GetMetaData(arg0, arg1); + md.set(Alembic::Abc::kApplicationNameKey, "Blender"); + md.set(Alembic::Abc::kUserDescriptionKey, scene_name); + + time_t raw_time; + time(&raw_time); + char buffer[128]; + +#if defined _WIN32 || defined _WIN64 + ctime_s(buffer, 128, &raw_time); +#else + ctime_r(&raw_time, buffer); +#endif + + const std::size_t buffer_len = strlen(buffer); + if (buffer_len > 0 && buffer[buffer_len - 1] == '\n') { + buffer[buffer_len - 1] = '\0'; + } + + md.set(Alembic::Abc::kDateWrittenKey, buffer); + + Alembic::Abc::ErrorHandler::Policy policy = GetErrorHandlerPolicyFromArgs(arg0, arg1); + +#ifdef WITH_ALEMBIC_HDF5 + if (!ogawa) { + return Alembic::Abc::OArchive(Alembic::AbcCoreHDF5::WriteArchive(), filename, md, policy); + } +#else + static_cast<void>(filename); + static_cast<void>(ogawa); +#endif + + Alembic::AbcCoreOgawa::WriteArchive archive_writer; + return Alembic::Abc::OArchive(archive_writer(ostream, md), Alembic::Abc::kWrapExisting, policy); +} + /* ************************************************************************** */ ExportSettings::ExportSettings() @@ -247,26 +299,25 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled) Alembic::Abc::Argument arg(md); -#ifdef WITH_ALEMBIC_HDF5 - if (!m_settings.export_ogawa) { - m_archive = Alembic::Abc::CreateArchiveWithInfo(Alembic::AbcCoreHDF5::WriteArchive(), - m_filename, - "Blender", - scene_name, - Alembic::Abc::ErrorHandler::kThrowPolicy, - arg); - } - else + /* Use stream to support unicode character paths on Windows. */ + if (m_settings.export_ogawa) { +#ifdef WIN32 + UTF16_ENCODE(m_filename); + std::wstring wstr(m_filename_16); + m_out_file.open(wstr.c_str(), std::ios::out | std::ios::binary); + UTF16_UN_ENCODE(m_filename); +#else + m_out_file.open(m_filename, std::ios::out | std::ios::binary); #endif - { - m_archive = Alembic::Abc::CreateArchiveWithInfo(Alembic::AbcCoreOgawa::WriteArchive(), - m_filename, - "Blender", - scene_name, - Alembic::Abc::ErrorHandler::kThrowPolicy, - arg); } + m_archive = create_archive(&m_out_file, + m_filename, + scene_name, + Alembic::Abc::ErrorHandler::kThrowPolicy, + arg, + m_settings.export_ogawa); + /* Create time samplings for transforms and shapes. */ TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_step_xform); diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h index 070eb9ea81a..6c242f973c4 100644 --- a/source/blender/alembic/intern/abc_exporter.h +++ b/source/blender/alembic/intern/abc_exporter.h @@ -24,6 +24,7 @@ #define __ABC_EXPORTER_H__ #include <Alembic/Abc/All.h> +#include <fstream> #include <map> #include <set> #include <vector> @@ -75,6 +76,7 @@ class AbcExporter { const char *m_filename; + std::ofstream m_out_file; Alembic::Abc::OArchive m_archive; unsigned int m_trans_sampling_index, m_shape_sampling_index; diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index f42c708b4c2..d057cc341f6 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -29,6 +29,12 @@ #include <Alembic/AbcCoreOgawa/All.h> #include <Alembic/AbcMaterial/IMaterial.h> +#include <fstream> + +#ifdef WIN32 +# include "utfconv.h" +#endif + #include "abc_camera.h" #include "abc_curves.h" #include "abc_hair.h" @@ -109,49 +115,97 @@ using Alembic::AbcGeom::V3fArraySamplePtr; using Alembic::AbcMaterial::IMaterial; -struct AbcArchiveHandle { - int unused; -}; - -ABC_INLINE IArchive *archive_from_handle(AbcArchiveHandle *handle) -{ - return reinterpret_cast<IArchive *>(handle); -} - -ABC_INLINE AbcArchiveHandle *handle_from_archive(IArchive *archive) +static IArchive open_archive(const std::string &filename, + const std::vector<std::istream *> &input_streams, + bool &is_hdf5) { - return reinterpret_cast<AbcArchiveHandle *>(archive); -} - -static IArchive *open_archive(const std::string &filename) -{ - Alembic::AbcCoreAbstract::ReadArraySampleCachePtr cache_ptr; - IArchive *archive; - try { - archive = new IArchive(Alembic::AbcCoreOgawa::ReadArchive(), - filename.c_str(), ErrorHandler::kThrowPolicy, - cache_ptr); + is_hdf5 = false; + Alembic::AbcCoreOgawa::ReadArchive archive_reader(input_streams); + + return IArchive(archive_reader(filename), + kWrapExisting, + ErrorHandler::kThrowPolicy); } catch (const Exception &e) { std::cerr << e.what() << '\n'; #ifdef WITH_ALEMBIC_HDF5 try { - archive = new IArchive(Alembic::AbcCoreHDF5::ReadArchive(), - filename.c_str(), ErrorHandler::kThrowPolicy, - cache_ptr); + is_hdf5 = true; + Alembic::AbcCoreAbstract::ReadArraySampleCachePtr cache_ptr; + + return IArchive(Alembic::AbcCoreHDF5::ReadArchive(), + filename.c_str(), ErrorHandler::kThrowPolicy, + cache_ptr); } catch (const Exception &) { std::cerr << e.what() << '\n'; - return NULL; + return IArchive(); } #else - return NULL; + return IArchive(); #endif } - return archive; + return IArchive(); +} + +/* Wrapper around an archive to be able to use streams so that unicode paths + * work on Windows (T49112), and to make sure the input stream remains valid as + * long as the archive is open. */ +class ArchiveWrapper { + IArchive m_archive; + std::ifstream m_infile; + std::vector<std::istream *> m_streams; + +public: + explicit ArchiveWrapper(const char *filename) + { +#ifdef WIN32 + UTF16_ENCODE(filename); + std::wstring wstr(filename_16); + m_infile.open(wstr.c_str(), std::ios::in | std::ios::binary); + UTF16_UN_ENCODE(filename); +#else + m_infile.open(filename, std::ios::in | std::ios::binary); +#endif + + m_streams.push_back(&m_infile); + + bool is_hdf5; + m_archive = open_archive(filename, m_streams, is_hdf5); + + /* We can't open an HDF5 file from a stream, so close it. */ + if (is_hdf5) { + m_infile.close(); + m_streams.clear(); + } + } + + bool valid() const + { + return m_archive.valid(); + } + + IObject getTop() + { + return m_archive.getTop(); + } +}; + +struct AbcArchiveHandle { + int unused; +}; + +ABC_INLINE ArchiveWrapper *archive_from_handle(AbcArchiveHandle *handle) +{ + return reinterpret_cast<ArchiveWrapper *>(handle); +} + +ABC_INLINE AbcArchiveHandle *handle_from_archive(ArchiveWrapper *archive) +{ + return reinterpret_cast<AbcArchiveHandle *>(archive); } //#define USE_NURBS @@ -247,9 +301,10 @@ static void gather_objects_paths(const IObject &object, ListBase *object_paths) AbcArchiveHandle *ABC_create_handle(const char *filename, ListBase *object_paths) { - IArchive *archive = open_archive(filename); + ArchiveWrapper *archive = new ArchiveWrapper(filename); - if (!archive) { + if (!archive->valid()) { + delete archive; return NULL; } @@ -582,12 +637,10 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa data->do_update = do_update; data->progress = progress; - IArchive *archive = open_archive(data->filename); + ArchiveWrapper *archive = new ArchiveWrapper(data->filename); - if (!archive || !archive->valid()) { - if (archive) { - delete archive; - } + if (!archive->valid()) { + delete archive; data->error_code = ABC_ARCHIVE_FAIL; return; } @@ -812,7 +865,7 @@ void ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence void ABC_get_transform(AbcArchiveHandle *handle, Object *ob, const char *object_path, float r_mat[4][4], float time, float scale) { - IArchive *archive = archive_from_handle(handle); + ArchiveWrapper *archive = archive_from_handle(handle); if (!archive || !archive->valid()) { return; @@ -1088,7 +1141,7 @@ DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, const char **err_str, int read_flag) { - IArchive *archive = archive_from_handle(handle); + ArchiveWrapper *archive = archive_from_handle(handle); if (!archive || !archive->valid()) { *err_str = "Invalid archive!"; |