![]() |
![]() |



Author: bane
Date Submitted: 2004-05-24 19:00:03
Downloads: pakstream_submission.h
/*
* pakstream.h - buffer and stream classes for writing to and reading from
* files through the Cipher pak file system.
*/
#ifndef pakstream_h
#define pakstream_h
#include <streambuf>
#include <iostream>
// Plus, include whatever you need to expose the cipher engine funcs
//////////////////////////////////////////////////////////////////////////
/*
* basic_pakstreambuf - A stream buffer for writing to and reading from
* cipher's pak filesystem. This class is generally not used directly
* by the user, but is used in the implementation of i/o streams (see
* below).
*/
template <class Ch, class Tr = std::char_traits<Ch> >
class basic_pakstreambuf : public std::basic_streambuf<Ch, Tr>
{
// HACK - There is a bug in Microsoft's STL string, where basic_string's
// notion of eof does not equal char_traits's eof. If you are using a
// different STL, try switching the comments on the following two lines.
//static const int_type eof = Tr::eof();
static const int_type eof = -1;
bool open_flag;
char_type *buf;
std::streamsize bufsz;
filehandle_t hfile;
int mode;
int filesz;
int filepos;
public:
basic_pakstreambuf()
{
open_flag = false;
buf = 0;
bufsz = 0;
hfile = 0;
mode = 0;
filesz = 0;
filepos = 0;
}
virtual ~basic_pakstreambuf()
{
close();
}
bool is_open()
{
return open_flag;
}
// File paths are always wide, regardless of template specialization.
// mode must be one of Cipher's FS_* constants.
bool open(const wchar_t *p, int mode)
{
filesz = cipher_fs_Open(p, mode, &hfile);
this->mode = mode;
open_flag = (hfile != 0);
return open_flag;
}
void close()
{
if (open_flag)
cipher_fs_Close(hfile);
hfile = 0;
filesz = 0;
filepos = 0;
mode = 0;
open_flag = false;
}
protected:
/*
* The protected interface determines this streambuf's policy, and is only
* used internally. For an understanding of each function's role, see
* Stroustrup's TC++PL, Sec. 21.6, as well as
* http://www.cplusplus.com/ref/iostream/ .
*
* Any un-overridden virtual functions are thus because the base class'
* default implementation is sufficient.
*/
virtual std::streambuf *setbuf(char_type *p, std::streamsize n)
{
if (!open_flag)
return this; // some sort of warning here would be nice
buf = p;
bufsz = n;
// We don't support simultaneous read-write modes - this would imply
// seeking, which is difficult for compressed files
if (mode == FS_READ) {
setp(buf, buf);
}
else if (mode == FS_WRITE || mode == FS_APPEND) {
setg(buf, buf, buf);
setp(buf, buf+bufsz);
}
return this;
}
virtual int showmanyc()
{
return egptr() - gptr();
}
virtual int_type underflow()
{
if (mode != FS_READ || !open_flag)
return eof;
if (filepos < filesz) {
cipher_fs_ReadBytes(buf, min(bufsz, filesz-filepos), hfile);
setg(buf, buf, (filesz-filepos < bufsz) ? buf+filesz-filepos : buf+bufsz);
filepos += filepos+bufsz < filesz ? bufsz : filesz-filepos;
}
if (filepos <= filesz) {
if (filepos == filesz) ++filepos;
return *gptr();
}
else return eof;
}
virtual int_type uflow()
{
if (mode != FS_READ || !open_flag)
return eof;
if (filepos < filesz) {
cipher_fs_ReadBytes(buf, min(bufsz, filesz-filepos), hfile);
setg(buf, buf, (filesz-filepos < bufsz) ? buf+filesz-filepos : buf+bufsz);
filepos += filepos+bufsz < filesz ? bufsz : filesz-filepos;
}
if (filepos <= filesz) {
gbump(1);
if (filepos == filesz) ++filepos;
return buf[0];
}
else return eof;
}
virtual int_type overflow(int_type c = eof)
{
if (!(mode == FS_WRITE || mode == FS_APPEND) || !open_flag)
return eof;
cipher_fs_WriteBytes(buf, bufsz, hfile);
if (c != eof)
cipher_fs_WriteBytes(&c, 1, hfile);
return 1; // any non-eof value indicates success
}
virtual int sync()
{
if (mode == FS_READ || !open_flag)
return 0;
cipher_fs_WriteBytes(buf, pptr()-buf, hfile);
setp(buf, buf+bufsz);
return 0;
}
};
//////////////////////////////////////////////////////////////////////////
/*
* The I/O streams. Provided here are two templated classes for I/O to/from
* Cipher's pak filesytem. Note however, that there is no stream class taht
* handles both input and output simultaneously.
*/
// NOTE: All of my error-handling mechanisms have been commented out.
// You will probably want to replace them with whatever logging/exception
// handling system you have set up.
//////////////////////////////////////////////////////////////////////////
/*
* basic_opakstream - A stream for sending output to a file in Cipher's
* pak filesystem. Use it essentially the same as std's basic_ofstream.
* There are convenient typedefs for narrow and wide specializations
* at the bottom of this file.
*/
template <class Ch, class Tr = std::char_traits<Ch> >
class basic_opakstream : public std::basic_ostream<Ch, Tr>
{
static const int BUF_SIZE = 512;
basic_pakstreambuf<Ch, Tr> sb;
Ch buffer[BUF_SIZE];
public:
basic_opakstream(const tchar_t *filename, int mode)
: basic_ostream<Ch,Tr>(&sb), sb()
{
if (!(mode == FS_WRITE || mode == FS_APPEND)) {
// TODO: an exception or somesuch
//LOG(ERROR, "Attempted to open opakstream with mode FS_READ!");
return;
}
if (!sb.open(filename, mode)) {
//LOG(ERROR, "Unable to open file for output:");
//cphrout << "\t\t\"" << filename << endl;
}
sb.pubsetbuf(buffer, BUF_SIZE);
}
virtual ~basic_opakstream() { }
};
/*
* basic_ipakstream - A stream for reading input from a file in Cipher's
* pak filesystem. Use it essentially the same as std's basic_ifstream.
* There are convenient typedefs for narrow and wide specializations
* at the bottom of this file.
*/
template <class Ch, class Tr = std::char_traits<Ch> >
class basic_ipakstream : public std::basic_istream<Ch, Tr>
{
static const int BUF_SIZE = 512;
basic_pakstreambuf<Ch, Tr> sb;
Ch buffer[BUF_SIZE];
public:
basic_ipakstream(const tchar_t *filename)
: basic_istream<Ch, Tr>(&sb), sb()
{
if (!sb.open(filename, FS_READ)) {
//LOG(ERROR, "Unable to open file for input:");
//cphrout << "\t\t\"" << filename << endl;
return;
}
sb.pubsetbuf(buffer, BUF_SIZE);
}
virtual ~basic_ipakstream() { }
};
/*
* Convenient typedefs
*/
typedef basic_opakstream<char> opakstream;
typedef basic_opakstream<wchar_t> wopakstream;
typedef basic_ipakstream<char> ipakstream;
typedef basic_ipakstream<wchar_t> wipakstream;
#endifThis contribution sort of follows in the theme of my previous submission for streaming output to the console. It's pretty straightforward. Include pakstream.h and you should (hopefully!) be able to do stuff like the following:
opakstream testout(_T("text/testout.txt"), FS_WRITE);
testout << "Hello, world!" << endl;
wopakstream wtestout(_T("text/wtestout.txt"), FS_WRITE);
wtestout << _T("Hello, wide world!") << endl;
ipakstream samplein(_T("scripts/sample_input"));
string s;
while (samplein >> s)
testout << s << endl;
The only major limitation right now is that there is no iopakstream. Please post any suggestions or bugs that you find!
[Recent Contributions] [Recent Source Code]
User Contributed Comments