/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- read_le32
- read_le16
- read_byte
- _autoclose
- read
- write
- seek
- go_to_end
- tell
- eof
- bad
- size
- close
- makeFileChannel
// tu_file.cpp -- Ignacio Castaņo, Thatcher Ulrich <tu@tulrich.com> 2003
// This source code has been donated to the Public Domain. Do
// whatever you want with it.
// A file class that can be customized with callbacks.
#include "tu_file.h"
#include <cstdio>
#include <boost/format.hpp>
#include <cerrno>
#include "GnashFileUtilities.h"
#include "utility.h"
#include "IOChannel.h"
#include "log.h"
namespace gnash {
/// An IOChannel that works on a C stdio file.
class tu_file : public IOChannel
{
public:
// Make a file from an ordinary FILE*.
tu_file(FILE* fp, bool autoclose);
~tu_file();
/// \brief Read a 32-bit word from a little-endian stream.
/// returning it as a native-endian word.
//
/// TODO: define what happens when the stream
/// is in error condition.
///
boost::uint32_t read_le32()
{
// read_byte() is boost::uint8_t, so no masks with 0xff are required.
boost::uint32_t result = static_cast<boost::uint32_t>(read_byte());
result |= static_cast<boost::uint32_t>(read_byte()) << 8;
result |= static_cast<boost::uint32_t>(read_byte()) << 16;
result |= static_cast<boost::uint32_t>(read_byte()) << 24;
return(result);
}
/// \brief Read a 16-bit word from a little-endian stream.
//
/// TODO: define what happens when the stream
/// is in error condition, see bad().
///
boost::uint16_t read_le16()
{
boost::uint16_t result = static_cast<boost::uint16_t>(read_byte());
result |= static_cast<boost::uint16_t>(read_byte()) << 8;
return(result);
}
/// \brief Read a single byte from the stream
//
/// TODO: define what happens when the stream
/// is in error condition, see bad().
///
boost::uint8_t read_byte() {
boost::uint8_t u;
read(&u, 1);
return u;
}
/// \brief Read the given number of bytes from the stream
//
/// TODO: define what happens when the stream
/// is in error condition, see bad().
///
std::streamsize read(void* dst, std::streamsize num);
/// \brief Write the given number of bytes to the stream
//
/// TODO: define what happens when the stream
/// is in error condition, see bad().
///
std::streamsize write(const void* src, std::streamsize num);
/// \brief Return current stream position
//
/// TODO: define what to return when the stream
/// is in error condition, see bad().
///
std::streampos tell() const;
/// \brief Seek to the specified position
//
///
/// TODO: define what happens when an error occurs, or
/// when we're already in an error condition
///
/// @return true on success, or false on failure.
///
bool seek(std::streampos p);
/// \brief Seek to the end of the stream
//
/// TODO: define what happens when an error occurs
///
void go_to_end();
/// \brief Return true if the end of the stream has been reached.
//
/// TODO: define what to return when in error condition
/// see bad().
///
bool eof() const;
/// \brief Return non-zero if the stream is in an error state
//
/// When the stream is in an error state there's nothing
/// you can do about it, just delete it and log the error.
///
/// There are some rough meaning for possible returned values
/// but I don't think they make much sense currently.
///
bool bad() const;
/// Get the size of the stream
size_t size() const;
private:
void close();
FILE* _data;
bool _autoclose;
};
//// Create a file from a standard file pointer.
tu_file::tu_file(FILE* fp, bool autoclose = false)
:
_data(fp),
_autoclose(autoclose)
{
}
tu_file::~tu_file()
{
// Close this file when destroyed unless not requested.
if (_autoclose) close();
}
// Return the number of bytes actually read. EOF or an error would
// cause that to not be equal to "bytes".
std::streamsize
tu_file::read(void* dst, std::streamsize bytes)
{
assert(dst);
return std::fread(dst, 1, bytes, _data);
}
// Return the number of bytes actually written.
std::streamsize
tu_file::write(const void* src, std::streamsize bytes)
{
assert(src);
return std::fwrite(src, 1, bytes, _data);
}
bool
tu_file::seek(std::streampos pos)
{
// TODO: optimize this by caching total stream size ?
if (pos > static_cast<std::streampos>(size())) return false;
std::clearerr(_data); // make sure EOF flag is cleared.
const int result = std::fseek(_data, pos, SEEK_SET);
if (result == EOF) {
return false;
}
assert (pos < std::numeric_limits<long>::max());
assert (std::ftell(_data) == pos);
return true;
}
void
tu_file::go_to_end()
{
const int err = std::fseek(_data, 0, SEEK_END);
if (err == -1) {
boost::format fmt = boost::format(
_("Error while seeking to end: %1%")) % strerror(errno);
throw IOException(fmt.str());
}
}
std::streampos
tu_file::tell() const
{
std::streampos ret = std::ftell(_data);
if (ret < 0) throw IOException("Error getting stream position");
assert(static_cast<size_t>(ret) <= size());
return ret;
}
bool
tu_file::eof() const
{
return std::feof(_data);
}
bool
tu_file::bad() const
{
if (!_data) return true;
return std::ferror(_data);
}
size_t
tu_file::size() const
{
assert(_data);
struct stat statbuf;
if (fstat(fileno(_data), &statbuf) < 0)
{
log_error("Could not fstat file");
return static_cast<size_t>(-1);
}
return statbuf.st_size;
}
void
tu_file::close()
{
assert(_data);
std::fclose(_data);
}
std::auto_ptr<IOChannel>
makeFileChannel(FILE* fp, bool close)
{
std::auto_ptr<IOChannel> ret(new tu_file(fp, close));
return ret;
}
} // end namespace gnash
// Local Variables:
// mode: C++
// indent-tabs-mode: t
// End: