summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2009-04-13 21:53:43 +0000
committerTavian Barnes <tavianator@gmail.com>2009-04-13 21:53:43 +0000
commitf9471e983baccaa4f43cfa43463c7a26bcb16c55 (patch)
treeeee3a8fee8071d78821444ef5b871557253b156d
parent11c2b9bbc790216eeb22a1e4d4de8161394c3fbf (diff)
downloaddimension-f9471e983baccaa4f43cfa43463c7a26bcb16c55.tar.xz
Use an RAII interface to fopencookie().
-rw-r--r--libdimensionxx/cookie.cpp114
-rw-r--r--libdimensionxx/dimensionxx/cookie.hpp32
-rw-r--r--libdimensionxx/png.cpp29
3 files changed, 86 insertions, 89 deletions
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*>(cookie);
+ FILE_Cookie* streams = reinterpret_cast<FILE_Cookie*>(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*>(cookie);
+ FILE_Cookie* streams = reinterpret_cast<FILE_Cookie*>(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*>(cookie);
+ FILE_Cookie* streams = reinterpret_cast<FILE_Cookie*>(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*>(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<void*>(cookie), "r", io_funcs);
+ m_file = fopencookie(reinterpret_cast<void*>(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<void*>(cookie), "w", io_funcs);
+ m_file = fopencookie(reinterpret_cast<void*>(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<void*>(cookie), "r+", io_funcs);
+ m_file = fopencookie(reinterpret_cast<void*>(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);
}
}