From f9471e983baccaa4f43cfa43463c7a26bcb16c55 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 13 Apr 2009 21:53:43 +0000 Subject: Use an RAII interface to fopencookie(). --- libdimensionxx/cookie.cpp | 114 +++++++++++++++------------------- libdimensionxx/dimensionxx/cookie.hpp | 32 +++++++++- libdimensionxx/png.cpp | 29 +++------ 3 files changed, 86 insertions(+), 89 deletions(-) (limited to 'libdimensionxx') diff --git a/libdimensionxx/cookie.cpp b/libdimensionxx/cookie.cpp index c3b1541..962137a 100644 --- a/libdimensionxx/cookie.cpp +++ b/libdimensionxx/cookie.cpp @@ -26,34 +26,24 @@ // standard way to map between them, so we use the nonportable GNU stdio // extension fopencookie(), which creates a FILE* with custom read/write/seek // functions. BSD also has a similar function, funopen(), which we should -// use too. Failing in all that, we should fall back on a tmpfile() buffer, -// but that would require an fclosecookie() function as well, to copy the -// buffer to the stream potentially. +// use too. Failing in all that, we should fall back on a tmpfile() buffer. namespace Dimension { namespace { - // Internal cookie type to hold the C++ streams. - struct Cookie - { - public: - std::istream* istr; - std::ostream* ostr; - }; - // Cookie read function ssize_t cookie_read(void* cookie, char* buf, size_t size) { - Cookie* streams = reinterpret_cast(cookie); + FILE_Cookie* streams = reinterpret_cast(cookie); // Do the unformatted read - streams->istr->read(buf, size); + streams->istr().read(buf, size); - if (streams->istr->eof() || streams->istr->good()) { - return streams->istr->gcount(); // This returns 0 on an immediate EOF - // for us. + if (streams->istr().eof() || streams->istr().good()) { + return streams->istr().gcount(); // This returns 0 on an immediate EOF + // for us. } else { // Some non-EOF error return -1; @@ -64,12 +54,12 @@ namespace Dimension ssize_t cookie_write(void* cookie, const char* buf, size_t size) { - Cookie* streams = reinterpret_cast(cookie); + FILE_Cookie* streams = reinterpret_cast(cookie); // Do the unformatted write - streams->ostr->write(buf, size); + streams->ostr().write(buf, size); - if (streams->ostr->good()) { + if (streams->ostr().good()) { // Write operation succeeded, so we must've written size bytes return size; } else { @@ -82,42 +72,42 @@ namespace Dimension int cookie_seek(void* cookie, off64_t* offset, int whence) { - Cookie* streams = reinterpret_cast(cookie); + FILE_Cookie* streams = reinterpret_cast(cookie); - if (streams->istr) { + if (streams->is_input()) { // If we have an input stream, seek it switch (whence) { case SEEK_SET: - streams->istr->seekg(*offset, std::ios::beg); + streams->istr().seekg(*offset, std::ios::beg); break; case SEEK_CUR: - streams->istr->seekg(*offset, std::ios::cur); + streams->istr().seekg(*offset, std::ios::cur); break; case SEEK_END: - streams->istr->seekg(*offset, std::ios::end); + streams->istr().seekg(*offset, std::ios::end); break; } - if (!streams->istr->good()) { + if (!streams->istr().good()) { // Seek failed return 1; } } - if (streams->ostr) { + if (streams->is_output()) { // If we have an output stream, seek it too switch (whence) { case SEEK_SET: - streams->ostr->seekp(*offset, std::ios::beg); + streams->ostr().seekp(*offset, std::ios::beg); break; case SEEK_CUR: - streams->ostr->seekp(*offset, std::ios::cur); + streams->ostr().seekp(*offset, std::ios::cur); break; case SEEK_END: - streams->ostr->seekp(*offset, std::ios::end); + streams->ostr().seekp(*offset, std::ios::end); } - if (!streams->ostr->good()) { + if (!streams->ostr().good()) { // Seek failed return 1; } @@ -126,64 +116,58 @@ namespace Dimension // Seek succeeded return 0; } - - // Cookie delete function - int - cookie_close(void* cookie) - { - // Free the cookie - delete reinterpret_cast(cookie); - } } - // Make an input FILE* - std::FILE* - fcookie(std::istream& istr) + // Make an input FILE_Cookie + FILE_Cookie::FILE_Cookie(std::istream& istr) + : m_istr(&istr), m_ostr(0) { - Cookie* cookie = new Cookie; - cookie->istr = &istr; - cookie->ostr = 0; - cookie_io_functions_t io_funcs; io_funcs.read = &cookie_read; io_funcs.write = 0; io_funcs.seek = &cookie_seek; - io_funcs.close = &cookie_close; + io_funcs.close = 0; - return fopencookie(reinterpret_cast(cookie), "r", io_funcs); + m_file = fopencookie(reinterpret_cast(this), "r", io_funcs); } - // Make an output FILE* - std::FILE* - fcookie(std::ostream& ostr) + // Make an output FILE_Cookie + FILE_Cookie::FILE_Cookie(std::ostream& ostr) + : m_istr(0), m_ostr(&ostr) { - Cookie* cookie = new Cookie; - cookie->istr = 0; - cookie->ostr = &ostr; - cookie_io_functions_t io_funcs; io_funcs.read = 0; io_funcs.write = &cookie_write; io_funcs.seek = &cookie_seek; - io_funcs.close = &cookie_close; + io_funcs.close = 0; - return fopencookie(reinterpret_cast(cookie), "w", io_funcs); + m_file = fopencookie(reinterpret_cast(this), "w", io_funcs); } - // Make an I/O FILE* - std::FILE* - fcookie(std::iostream& iostr) + // Make an I/O FILE_Cookie + FILE_Cookie::FILE_Cookie(std::istream& istr, std::ostream& ostr) + : m_istr(&istr), m_ostr(&ostr) { - Cookie* cookie = new Cookie; - cookie->istr = &iostr; - cookie->ostr = &iostr; - cookie_io_functions_t io_funcs; io_funcs.read = &cookie_read; io_funcs.write = &cookie_write; io_funcs.seek = &cookie_seek; - io_funcs.close = &cookie_close; + io_funcs.close = 0; - return fopencookie(reinterpret_cast(cookie), "r+", io_funcs); + m_file = fopencookie(reinterpret_cast(this), "r+", io_funcs); } + + // Close the file + FILE_Cookie::~FILE_Cookie() { std::fclose(m_file); } + + FILE* FILE_Cookie::file() { return m_file; } + const FILE* FILE_Cookie::file() const { return m_file; } + + bool FILE_Cookie::is_input() const { return m_istr; } + bool FILE_Cookie::is_output() const { return m_ostr; } + + std::istream& FILE_Cookie::istr() { return *m_istr; } + const std::istream& FILE_Cookie::istr() const { return *m_istr; } + std::ostream& FILE_Cookie::ostr() { return *m_ostr; } + const std::ostream& FILE_Cookie::ostr() const { return *m_ostr; } } diff --git a/libdimensionxx/dimensionxx/cookie.hpp b/libdimensionxx/dimensionxx/cookie.hpp index 639fbfe..a2a3324 100644 --- a/libdimensionxx/dimensionxx/cookie.hpp +++ b/libdimensionxx/dimensionxx/cookie.hpp @@ -30,9 +30,35 @@ namespace Dimension { - std::FILE* fcookie(std::istream& istr); - std::FILE* fcookie(std::ostream& ostr); - std::FILE* fcookie(std::iostream& iostr); + // Simple RAII class for FILE*'s which interface with a C++ stream. + class FILE_Cookie + { + public: + FILE_Cookie(std::istream& istr); + FILE_Cookie(std::ostream& ostr); + FILE_Cookie(std::istream& istr, std::ostream& ostr); + ~FILE_Cookie(); + + FILE* file(); + const FILE* file() const; + + bool is_input() const; + bool is_output() const; + + std::istream& istr(); + const std::istream& istr() const; + std::ostream& ostr(); + const std::ostream& ostr() const; + + private: + std::FILE* m_file; + std::istream* m_istr; + std::ostream* m_ostr; + + // Copying prohibited + FILE_Cookie(const FILE_Cookie& cookie); + FILE_Cookie& operator=(const FILE_Cookie& cookie); + }; } #endif /* DIMENSIONXX_COOKIE_HPP */ diff --git a/libdimensionxx/png.cpp b/libdimensionxx/png.cpp index cd4925e..8a2770b 100644 --- a/libdimensionxx/png.cpp +++ b/libdimensionxx/png.cpp @@ -40,7 +40,7 @@ namespace Dimension } } - // Write the PNG file. Uses the fcookie() interface to make a FILE* + // Write the PNG file. Uses the FILE_Cookie() interface to make a FILE* // corresponding to an std::ostream (including std::ostringstream, etc). void PNG_Canvas::write() { @@ -55,25 +55,19 @@ namespace Dimension " stream."); } - FILE* file = fcookie(*m_ostr); - if (!file) { - // fcookie() shouldn't fail, really - throw Dimension_Error("Couldn't create C++/C IO interface when writing" - " canvas to PNG."); - } + // Make the C++/C I/O interface + FILE_Cookie cookie(*m_ostr); // Write the PNG file - if (dmnsn_png_write_canvas(m_canvas, file)) { + if (dmnsn_png_write_canvas(m_canvas, cookie.file())) { // The actual write operation failed, for some reason. - std::fclose(file); throw Dimension_Error("Writing canvas to PNG failed."); } - std::fclose(file); m_written = true; // We've written the file now, don't do it again } - // Read a canvas from a PNG file. Uses the fcookie() interface to make a + // Read a canvas from a PNG file. Uses the FILE_Cookie() interface to make a // FILE* corresponding to an std::istream (including std::istringstream, etc). void PNG_Canvas::read() { @@ -84,20 +78,13 @@ namespace Dimension " stream."); } - FILE* file = fcookie(*m_istr); - if (!file) { - // fcookie() shouldn't fail, really - throw Dimension_Error("Couldn't create C++/C IO interface when reading" - " canvas from PNG."); - } + // Make the C++/C I/O interface + FILE_Cookie cookie(*m_istr); // Read the canvas from a PNG file - if (!(m_canvas = dmnsn_png_read_canvas(file))) { + if (!(m_canvas = dmnsn_png_read_canvas(cookie.file()))) { // The read operation failed - std::fclose(file); throw Dimension_Error("Reading canvas from PNG failed."); } - - std::fclose(file); } } -- cgit v1.2.3