Skip to content

Commit

Permalink
Add mechanism for test programs to use win32 wide filename fix when m…
Browse files Browse the repository at this point in the history
…anually creating std::fstreams

Signed-off-by: Kimball Thurston <[email protected]>
  • Loading branch information
kdt3rd committed Aug 12, 2019
1 parent 1d0b240 commit e0ac10e
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 40 deletions.
13 changes: 10 additions & 3 deletions OpenEXR/IlmImfFuzzTest/fuzzFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@

#include <iostream>
#include <fstream>
#include "../IlmImfTest/TestUtilFStream.h"

// Handle the case when the custom namespace is not exposed
#include <OpenEXRConfig.h>
Expand All @@ -58,7 +59,9 @@ namespace {
Int64
lengthOfFile (const char fileName[])
{
ifstream ifs (fileName, ios_base::binary);
ifstream ifs;
testutil::OpenStreamWithUTF8Name (
ifs, fileName, ios::in | ios_base::binary);

if (!ifs)
return 0;
Expand All @@ -80,7 +83,9 @@ fuzzFile (const char goodFile[],
// Read the input file.
//

ifstream ifs (goodFile, ios_base::binary);
ifstream ifs;
testutil::OpenStreamWithUTF8Name (
ifs, goodFile, ios::in | ios_base::binary);

if (!ifs)
THROW_ERRNO ("Cannot open file " << goodFile << " (%T).");
Expand Down Expand Up @@ -110,7 +115,9 @@ fuzzFile (const char goodFile[],
// Save the damaged file contents in the output file.
//

ofstream ofs (brokenFile, ios_base::binary);
ofstream ofs;
testutil::OpenStreamWithUTF8Name (
ofs, brokenFile, ios::out | ios_base::binary);

if (!ofs)
THROW_ERRNO ("Cannot open file " << brokenFile << " (%T)." << endl);
Expand Down
135 changes: 135 additions & 0 deletions OpenEXR/IlmImfTest/TestUtilFStream.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright Contributors to the OpenEXR Project.

#pragma once

#ifndef INCLUDE_TestUtilFStream_h_
#define INCLUDE_TestUtilFStream_h_ 1

#include <fstream>
#include <string>

#ifdef _WIN32
# define VC_EXTRALEAN
# include <string.h>
# include <windows.h>
# include <io.h>
# include <fcntl.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <share.h>
#endif

namespace testutil
{
#ifdef _WIN32
inline std::wstring
WidenFilename (const char* filename)
{
std::wstring ret;
int fnlen = static_cast<int> (strlen (filename));
int len = MultiByteToWideChar (CP_UTF8, 0, filename, fnlen, NULL, 0);
if (len > 0)
{
ret.resize (len);
MultiByteToWideChar (CP_UTF8, 0, filename, fnlen, &ret[0], len);
}
return ret;
}

// This is a big work around mechanism for compiling using mingw / gcc under windows
// until mingw 9 where they add the wide filename version of open
# if (defined(__GLIBCXX__) && !(defined(_GLIBCXX_HAVE_WFOPEN) && defined(_GLIBCXX_USE_WCHAR_T)))
# define USE_WIDEN_FILEBUF 1
template <typename CharT, typename TraitsT>
class WidenFilebuf : public std::basic_filebuf<CharT, TraitsT>
{
inline int mode_to_flags (std::ios_base::openmode mode)
{
int flags = 0;
if (mode & std::ios_base::in) flags |= _O_RDONLY;
if (mode & std::ios_base::out)
{
flags |= _O_WRONLY;
flags |= _O_CREAT;
if (mode & std::ios_base::app) flags |= _O_APPEND;
if (mode & std::ios_base::trunc) flags |= _O_TRUNC;
}
if (mode & std::ios_base::binary)
flags |= _O_BINARY;
else
flags |= _O_TEXT;
return flags;
}

public:
using base_filebuf = std::basic_filebuf<CharT, TraitsT>;
inline base_filebuf* wide_open (std::wstring& fn, std::ios_base::openmode m)
{
if (this->is_open () || fn.empty ())
return nullptr;

int fd;
errno_t e = _wsopen_s (
&fd,
fn.c_str (),
mode_to_flags (m),
_SH_DENYNO,
_S_IREAD | _S_IWRITE);
if (e != 0)
return nullptr;

// sys_open will do an fdopen internally which will then clean up the fd upon close
this->_M_file.sys_open (fd, m);
if (this->is_open ())
{
// reset the internal state, these members are consistent between gcc versions 4.3 - 9
// but at 9, the wfopen stuff should become available, such that this will no longer be
// active
this->_M_allocate_internal_buffer ();
this->_M_mode = m;
this->_M_reading = false;
this->_M_writing = false;
this->_M_set_buffer (-1);
this->_M_state_last = this->_M_state_cur = this->_M_state_beg;

if ((m & std::ios_base::ate) &&
this->seekoff (0, std::ios_base::end, m) ==
static_cast<typename base_filebuf::pos_type> (-1))
{
this->close ();
return nullptr;
}
}
return this;
}
};
# endif // __GLIBCXX__
#endif // _WIN32

template <typename StreamType>
inline void
OpenStreamWithUTF8Name (
StreamType& is, const char* filename, std::ios_base::openmode mode)
{
#ifdef _WIN32
std::wstring wfn = WidenFilename (filename);
# ifdef USE_WIDEN_FILEBUF
using CharT = typename StreamType::char_type;
using TraitsT = typename StreamType::traits_type;
using wbuf = WidenFilebuf<CharT, TraitsT>;
if (!static_cast<wbuf*> (is.rdbuf ())->wide_open (wfn, mode))
is.setstate (std::ios_base::failbit);
else
is.clear ();
# else
is.rdbuf ()->open (wfn.c_str (), mode);
# endif
#else
is.rdbuf ()->open (filename, mode);
#endif
}

} // namespace testutil

#endif // INCLUDE_TestUtilFStream_h_
6 changes: 4 additions & 2 deletions OpenEXR/IlmImfTest/testBackwardCompatibility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#endif

#include "testBackwardCompatibility.h"
#include "TestUtilFStream.h"

#include <ImfArray.h>
#include <ImfHeader.h>
Expand Down Expand Up @@ -104,8 +105,9 @@ const int H = 197;
void
diffImageFiles (const char * fn1, const char * fn2)
{
ifstream i1 (fn1, ios::binary);
ifstream i2 (fn2, ios::binary);
ifstream i1, i2;
testutil::OpenStreamWithUTF8Name (i1, fn1, ios::in | ios::binary);
testutil::OpenStreamWithUTF8Name (i2, fn2, ios::in | ios::binary);

if(!i1.good()){THROW (IEX_NAMESPACE::BaseExc, string("cannot open ") + string(fn1));}
if(!i2.good()){THROW (IEX_NAMESPACE::BaseExc, string("cannot open ") + string(fn2));}
Expand Down
55 changes: 35 additions & 20 deletions OpenEXR/IlmImfTest/testExistingStreams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#include <vector>
#include <ImfChannelList.h>

#include "TestUtilFStream.h"

using namespace OPENEXR_IMF_NAMESPACE;
using namespace std;
Expand Down Expand Up @@ -139,7 +140,9 @@ MMIFStream::MMIFStream (const char fileName[]):
_length (0),
_pos (0)
{
std::ifstream ifs (fileName, ios_base::binary);
std::ifstream ifs;
testutil::OpenStreamWithUTF8Name (
ifs, fileName, ios::in | ios_base::binary);

//
// Get length of file
Expand Down Expand Up @@ -229,19 +232,23 @@ writeReadScanLines (const char fileName[],

{
cout << "writing";
remove (fileName);
std::ofstream os (fileName, ios_base::binary);
StdOFStream ofs (os, fileName);
RgbaOutputFile out (ofs, header, WRITE_RGBA);
out.setFrameBuffer (&p1[0][0], 1, width);
out.writePixels (height);
remove (fileName);
std::ofstream os;
testutil::OpenStreamWithUTF8Name (
os, fileName, ios::out | ios_base::binary);
StdOFStream ofs (os, fileName);
RgbaOutputFile out (ofs, header, WRITE_RGBA);
out.setFrameBuffer (&p1[0][0], 1, width);
out.writePixels (height);
}

{
cout << ", reading";
std::ifstream is (fileName, ios_base::binary);
StdIFStream ifs (is, fileName);
RgbaInputFile in (ifs);
std::ifstream is;
testutil::OpenStreamWithUTF8Name (
is, fileName, ios::in | ios_base::binary);
StdIFStream ifs (is, fileName);
RgbaInputFile in (ifs);

const Box2i &dw = in.dataWindow();
int w = dw.max.x - dw.min.x + 1;
Expand Down Expand Up @@ -333,7 +340,9 @@ writeReadMultiPart (const char fileName[],
{
cout << "writing";
remove (fileName);
std::ofstream os (fileName, ios_base::binary);
std::ofstream os;
testutil::OpenStreamWithUTF8Name (
os, fileName, ios::out | ios_base::binary);
StdOFStream ofs (os, fileName);
MultiPartOutputFile out (ofs, &headers[0],2);
FrameBuffer f;
Expand All @@ -352,7 +361,9 @@ writeReadMultiPart (const char fileName[],

{
cout << ", reading";
std::ifstream is (fileName, ios_base::binary);
std::ifstream is;
testutil::OpenStreamWithUTF8Name (
is, fileName, ios::in | ios_base::binary);
StdIFStream ifs (is, fileName);
MultiPartInputFile in (ifs);

Expand Down Expand Up @@ -464,19 +475,23 @@ writeReadTiles (const char fileName[],

{
cout << "writing";
remove (fileName);
std::ofstream os (fileName, ios_base::binary);
StdOFStream ofs (os, fileName);
TiledRgbaOutputFile out (ofs, header, WRITE_RGBA, 20, 20, ONE_LEVEL);
out.setFrameBuffer (&p1[0][0], 1, width);
remove (fileName);
std::ofstream os;
testutil::OpenStreamWithUTF8Name (
os, fileName, ios_base::out | ios_base::binary);
StdOFStream ofs (os, fileName);
TiledRgbaOutputFile out (ofs, header, WRITE_RGBA, 20, 20, ONE_LEVEL);
out.setFrameBuffer (&p1[0][0], 1, width);
out.writeTiles (0, out.numXTiles() - 1, 0, out.numYTiles() - 1);
}

{
cout << ", reading";
std::ifstream is (fileName, ios_base::binary);
StdIFStream ifs (is, fileName);
TiledRgbaInputFile in (ifs);
std::ifstream is;
testutil::OpenStreamWithUTF8Name (
is, fileName, ios::in | ios_base::binary);
StdIFStream ifs (is, fileName);
TiledRgbaInputFile in (ifs);

const Box2i &dw = in.dataWindow();
int w = dw.max.x - dw.min.x + 1;
Expand Down
5 changes: 4 additions & 1 deletion OpenEXR/IlmImfTest/testMagic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
#include <stdio.h>
#include <assert.h>

#include "TestUtilFStream.h"

#ifndef ILM_IMF_TEST_IMAGEDIR
#define ILM_IMF_TEST_IMAGEDIR
#endif
Expand All @@ -60,7 +62,8 @@ testFile1 (const char fileName[], bool isImfFile)
{
cout << fileName << " " << flush;

ifstream f (fileName, ios_base::binary);
ifstream f;
testutil::OpenStreamWithUTF8Name (f, fileName, ios::in | ios_base::binary);
assert (!!f);

char bytes[4];
Expand Down
32 changes: 18 additions & 14 deletions OpenEXR/IlmImfTest/testPreviewImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <fstream>
#include <stdio.h>
#include <assert.h>
#include "TestUtilFStream.h"

#ifndef ILM_IMF_TEST_IMAGEDIR
#define ILM_IMF_TEST_IMAGEDIR
Expand Down Expand Up @@ -179,20 +180,23 @@ readWriteFiles (const char fileName1[],
cout << "comparing files " << fileName2 << " and " << fileName3 << endl;

{
ifstream file2 (fileName2, std::ios_base::binary);
ifstream file3 (fileName3, std::ios_base::binary);

while (true)
{
int c2 = file2.get();
int c3 = file3.get();

if (file2.eof())
break;

assert (c2 == c3);
assert (!!file2 && !!file3);
}
ifstream file2, file3;
testutil::OpenStreamWithUTF8Name (
file2, fileName2, std::ios_base::in | std::ios_base::binary);
testutil::OpenStreamWithUTF8Name (
file3, fileName3, std::ios_base::in | std::ios_base::binary);

while (true)
{
int c2 = file2.get();
int c3 = file3.get();

if (file2.eof())
break;

assert (c2 == c3);
assert (!!file2 && !!file3);
}
}

remove (fileName2);
Expand Down

0 comments on commit e0ac10e

Please sign in to comment.