mirror of
https://github.com/0ldsk00l/nestopia.git
synced 2025-04-02 10:31:51 -04:00
585 lines
12 KiB
C++
585 lines
12 KiB
C++
////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Nestopia - NES/Famicom emulator written in C++
|
|
//
|
|
// Copyright (C) 2003-2008 Martin Freij
|
|
//
|
|
// This file is part of Nestopia.
|
|
//
|
|
// Nestopia is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Nestopia is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Nestopia; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <iostream>
|
|
#include "NstIoFile.hpp"
|
|
#include "NstIoStream.hpp"
|
|
|
|
namespace Nestopia
|
|
{
|
|
namespace Io
|
|
{
|
|
namespace Stream
|
|
{
|
|
class In::FileStream : public std::istream
|
|
{
|
|
public:
|
|
|
|
class Buffer : public std::streambuf
|
|
{
|
|
public:
|
|
|
|
explicit Buffer(const File&,bool=false);
|
|
explicit Buffer(GenericString);
|
|
~Buffer();
|
|
|
|
protected:
|
|
|
|
const File& file;
|
|
|
|
private:
|
|
|
|
const bool internal;
|
|
|
|
int_type underflow();
|
|
int_type uflow();
|
|
std::streamsize xsgetn(char*,std::streamsize);
|
|
std::streampos seekoff(std::streamoff,std::ios::seekdir,std::ios::openmode);
|
|
std::streampos seekpos(std::streampos,std::ios::openmode);
|
|
|
|
#if NST_MSVC >= 1400 // ugh
|
|
std::streamsize _Xsgetn_s(char*,std::size_t,std::streamsize);
|
|
#endif
|
|
};
|
|
|
|
private:
|
|
|
|
Buffer buffer;
|
|
|
|
public:
|
|
|
|
explicit FileStream(const File& f)
|
|
: std::istream(&buffer), buffer(f) {}
|
|
|
|
explicit FileStream(GenericString filename)
|
|
: std::istream(&buffer), buffer(filename) {}
|
|
};
|
|
|
|
class In::BufferStream : public std::istream
|
|
{
|
|
class Buffer : public std::streambuf
|
|
{
|
|
public:
|
|
|
|
explicit Buffer(const void*,uint);
|
|
|
|
private:
|
|
|
|
uint pos;
|
|
const char* const data;
|
|
const uint size;
|
|
|
|
int_type underflow();
|
|
int_type uflow();
|
|
std::streamsize xsgetn(char*,std::streamsize);
|
|
std::streampos seekoff(std::streamoff,std::ios::seekdir,std::ios::openmode);
|
|
std::streampos seekpos(std::streampos,std::ios::openmode);
|
|
|
|
#if NST_MSVC >= 1400 // ugh
|
|
std::streamsize _Xsgetn_s(char*,std::size_t,std::streamsize);
|
|
#endif
|
|
};
|
|
|
|
Buffer buffer;
|
|
|
|
public:
|
|
|
|
explicit BufferStream(const void* data,uint size)
|
|
: std::istream(&buffer), buffer(data,size) {}
|
|
};
|
|
|
|
In::In(const File& file)
|
|
: stream(*new FileStream(file))
|
|
{
|
|
}
|
|
|
|
In::In(GenericString filename)
|
|
: stream(*new FileStream(filename))
|
|
{
|
|
}
|
|
|
|
In::In(const Collection::Buffer& buffer)
|
|
: stream(*new BufferStream(buffer.Ptr(),buffer.Size()))
|
|
{
|
|
}
|
|
|
|
In::In(const void* data,uint size)
|
|
: stream(*new BufferStream(data,size))
|
|
{
|
|
}
|
|
|
|
In::~In()
|
|
{
|
|
delete &stream;
|
|
}
|
|
|
|
In::FileStream::Buffer::Buffer(const File& f,bool i)
|
|
: file(f), internal(i)
|
|
{
|
|
setg( NULL, NULL, NULL );
|
|
}
|
|
|
|
In::FileStream::Buffer::Buffer(GenericString filename)
|
|
: file(*new Io::File(filename,Io::File::READ|Io::File::EXISTING)), internal(true)
|
|
{
|
|
setg( NULL, NULL, NULL );
|
|
}
|
|
|
|
In::FileStream::Buffer::~Buffer()
|
|
{
|
|
if (internal)
|
|
delete &file;
|
|
}
|
|
|
|
#ifdef NST_MSVC_OPTIMIZE
|
|
#pragma optimize("t", on)
|
|
#endif
|
|
|
|
In::FileStream::Buffer::int_type In::FileStream::Buffer::underflow()
|
|
{
|
|
try
|
|
{
|
|
return file.Peek8();
|
|
}
|
|
catch (...)
|
|
{
|
|
return traits_type::eof();
|
|
}
|
|
}
|
|
|
|
In::FileStream::Buffer::int_type In::FileStream::Buffer::uflow()
|
|
{
|
|
try
|
|
{
|
|
return file.Read8();
|
|
}
|
|
catch (...)
|
|
{
|
|
return traits_type::eof();
|
|
}
|
|
}
|
|
|
|
std::streamsize In::FileStream::Buffer::xsgetn(char* output,std::streamsize count)
|
|
{
|
|
NST_ASSERT( count >= 0 );
|
|
|
|
try
|
|
{
|
|
return file.ReadSome( output, count );
|
|
}
|
|
catch (...)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#if NST_MSVC >= 1400
|
|
std::streamsize In::FileStream::Buffer::_Xsgetn_s(char* output,std::size_t,std::streamsize count)
|
|
{
|
|
return Buffer::xsgetn( output, count );
|
|
}
|
|
#endif
|
|
|
|
std::streampos In::FileStream::Buffer::seekoff(std::streamoff off,std::ios::seekdir dir,std::ios::openmode)
|
|
{
|
|
NST_ASSERT( (dir == std::ios::beg || dir == std::ios::cur || dir == std::ios::end) );
|
|
|
|
try
|
|
{
|
|
return file.Seek
|
|
(
|
|
dir == std::ios::beg ? File::BEGIN :
|
|
dir == std::ios::end ? File::END :
|
|
File::CURRENT,
|
|
off
|
|
);
|
|
}
|
|
catch (...)
|
|
{
|
|
return std::streamoff(-1);
|
|
}
|
|
}
|
|
|
|
std::streampos In::FileStream::Buffer::seekpos(std::streampos p,std::ios::openmode mode)
|
|
{
|
|
return seekoff( p, std::ios::beg, mode );
|
|
}
|
|
|
|
#ifdef NST_MSVC_OPTIMIZE
|
|
#pragma optimize("", on)
|
|
#endif
|
|
|
|
In::BufferStream::Buffer::Buffer(const void* d,uint s)
|
|
: pos(0), data(static_cast<const char*>(d)), size(s)
|
|
{
|
|
setg( NULL, NULL, NULL );
|
|
}
|
|
|
|
#ifdef NST_MSVC_OPTIMIZE
|
|
#pragma optimize("t", on)
|
|
#endif
|
|
|
|
In::BufferStream::Buffer::int_type In::BufferStream::Buffer::underflow()
|
|
{
|
|
NST_VERIFY( pos <= size );
|
|
return pos < size ? data[pos] : traits_type::eof();
|
|
}
|
|
|
|
In::BufferStream::Buffer::int_type In::BufferStream::Buffer::uflow()
|
|
{
|
|
NST_VERIFY( pos <= size );
|
|
return pos < size ? data[pos++] : traits_type::eof();
|
|
}
|
|
|
|
std::streamsize In::BufferStream::Buffer::xsgetn(char* output,std::streamsize count)
|
|
{
|
|
NST_ASSERT( count >= 0 );
|
|
NST_VERIFY( count + pos <= size + 1 );
|
|
|
|
if (count + pos > size)
|
|
count = pos < size ? size - pos : 0;
|
|
|
|
std::memcpy( output, data + pos, count );
|
|
pos += count;
|
|
|
|
return count;
|
|
}
|
|
|
|
#if NST_MSVC >= 1400
|
|
std::streamsize In::BufferStream::Buffer::_Xsgetn_s(char* output,std::size_t,std::streamsize count)
|
|
{
|
|
return Buffer::xsgetn( output, count );
|
|
}
|
|
#endif
|
|
|
|
std::streampos In::BufferStream::Buffer::seekoff(std::streamoff off,std::ios::seekdir dir,std::ios::openmode mode)
|
|
{
|
|
NST_ASSERT( (mode == std::ios::in) && (dir == std::ios::beg || dir == std::ios::cur || dir == std::ios::end) );
|
|
|
|
if (dir == std::ios::cur)
|
|
{
|
|
off += int(pos);
|
|
}
|
|
else if (dir == std::ios::end)
|
|
{
|
|
off += int(size);
|
|
}
|
|
|
|
NST_VERIFY( off >= 0 && off <= size );
|
|
|
|
if (off >= 0 && off <= size)
|
|
{
|
|
pos = off;
|
|
return off;
|
|
}
|
|
else
|
|
{
|
|
return std::streamoff(-1);
|
|
}
|
|
}
|
|
|
|
std::streampos In::BufferStream::Buffer::seekpos(std::streampos p,std::ios::openmode mode)
|
|
{
|
|
return seekoff( p, std::ios::beg, mode );
|
|
}
|
|
|
|
#ifdef NST_MSVC_OPTIMIZE
|
|
#pragma optimize("", on)
|
|
#endif
|
|
|
|
class Out::FileStream : public std::ostream
|
|
{
|
|
public:
|
|
|
|
class Buffer : public In::FileStream::Buffer
|
|
{
|
|
public:
|
|
|
|
explicit Buffer(const File&,bool=false);
|
|
explicit Buffer(GenericString);
|
|
|
|
private:
|
|
|
|
int_type overflow(int_type);
|
|
std::streamsize xsputn(const char*,std::streamsize);
|
|
};
|
|
|
|
private:
|
|
|
|
Buffer buffer;
|
|
|
|
public:
|
|
|
|
explicit FileStream(const File& f)
|
|
: std::ostream(&buffer), buffer(f) {}
|
|
|
|
explicit FileStream(GenericString filename)
|
|
: std::ostream(&buffer), buffer(filename) {}
|
|
};
|
|
|
|
class Out::BufferStream : public std::ostream
|
|
{
|
|
class Buffer : public std::streambuf
|
|
{
|
|
public:
|
|
|
|
explicit Buffer(Collection::Buffer&);
|
|
|
|
private:
|
|
|
|
uint pos;
|
|
Collection::Buffer& data;
|
|
|
|
int_type overflow(int_type);
|
|
std::streamsize xsputn(const char*,std::streamsize);
|
|
std::streampos seekoff(std::streamoff,std::ios::seekdir,std::ios::openmode);
|
|
std::streampos seekpos(std::streampos,std::ios::openmode);
|
|
};
|
|
|
|
Buffer buffer;
|
|
|
|
public:
|
|
|
|
explicit BufferStream(Collection::Buffer& b)
|
|
: std::ostream(&buffer), buffer(b) {}
|
|
};
|
|
|
|
Out::Out(const File& file)
|
|
: stream(*new FileStream(file))
|
|
{
|
|
}
|
|
|
|
Out::Out(GenericString filename)
|
|
: stream(*new FileStream(filename))
|
|
{
|
|
}
|
|
|
|
Out::Out(Collection::Buffer& buffer)
|
|
: stream(*new BufferStream(buffer))
|
|
{
|
|
}
|
|
|
|
Out::~Out()
|
|
{
|
|
delete &stream;
|
|
}
|
|
|
|
Out::FileStream::Buffer::Buffer(const File& file,bool i)
|
|
: In::FileStream::Buffer(file,i)
|
|
{
|
|
setp( NULL, NULL );
|
|
}
|
|
|
|
Out::FileStream::Buffer::Buffer(GenericString filename)
|
|
: In::FileStream::Buffer(*new Io::File(filename,Io::File::WRITE|Io::File::EMPTY),true)
|
|
{
|
|
setp( NULL, NULL );
|
|
}
|
|
|
|
#ifdef NST_MSVC_OPTIMIZE
|
|
#pragma optimize("t", on)
|
|
#endif
|
|
|
|
Out::FileStream::Buffer::int_type Out::FileStream::Buffer::overflow(int_type c)
|
|
{
|
|
if (!traits_type::eq_int_type(traits_type::eof(),c))
|
|
{
|
|
try
|
|
{
|
|
file.Write8( c );
|
|
}
|
|
catch (...)
|
|
{
|
|
c = traits_type::eof();
|
|
}
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
std::streamsize Out::FileStream::Buffer::xsputn(const char* input,std::streamsize count)
|
|
{
|
|
NST_ASSERT( count >= 0 );
|
|
|
|
try
|
|
{
|
|
return file.WriteSome( input, count );
|
|
}
|
|
catch (...)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#ifdef NST_MSVC_OPTIMIZE
|
|
#pragma optimize("", on)
|
|
#endif
|
|
|
|
Out::BufferStream::Buffer::Buffer(Collection::Buffer& buffer)
|
|
: pos(0), data(buffer)
|
|
{
|
|
setp( NULL, NULL );
|
|
}
|
|
|
|
#ifdef NST_MSVC_OPTIMIZE
|
|
#pragma optimize("t", on)
|
|
#endif
|
|
|
|
Out::BufferStream::Buffer::int_type Out::BufferStream::Buffer::overflow(int_type c)
|
|
{
|
|
if (!traits_type::eq_int_type(traits_type::eof(),c))
|
|
{
|
|
if (data.Size() == pos)
|
|
{
|
|
++pos;
|
|
data.PushBack( c );
|
|
}
|
|
else if (data.Size() > pos)
|
|
{
|
|
data[pos++] = c;
|
|
}
|
|
else
|
|
{
|
|
c = traits_type::eof();
|
|
}
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
std::streamsize Out::BufferStream::Buffer::xsputn(const char* input,std::streamsize count)
|
|
{
|
|
NST_ASSERT( count >= 0 );
|
|
|
|
const uint cur = pos;
|
|
pos += count;
|
|
|
|
if (pos > data.Capacity())
|
|
data.Reserve( pos * 2 );
|
|
|
|
if (pos > data.Size())
|
|
data.SetTo( pos );
|
|
|
|
std::memcpy( data.Ptr() + cur, input, count );
|
|
|
|
return count;
|
|
}
|
|
|
|
std::streampos Out::BufferStream::Buffer::seekoff(std::streamoff off,std::ios::seekdir dir,std::ios::openmode mode)
|
|
{
|
|
NST_ASSERT( (mode == std::ios::out) && (dir == std::ios::beg || dir == std::ios::cur || dir == std::ios::end) );
|
|
|
|
if (dir == std::ios::cur)
|
|
{
|
|
off += int(pos);
|
|
}
|
|
else if (dir == std::ios::end)
|
|
{
|
|
off += int(data.Size());
|
|
}
|
|
|
|
NST_VERIFY( off >= 0 && off <= data.Size() );
|
|
|
|
if (off >= 0 && off <= data.Size())
|
|
{
|
|
pos = off;
|
|
return off;
|
|
}
|
|
else
|
|
{
|
|
return std::streamoff(-1);
|
|
}
|
|
}
|
|
|
|
std::streampos Out::BufferStream::Buffer::seekpos(std::streampos p,std::ios::openmode mode)
|
|
{
|
|
return seekoff( p, std::ios::beg, mode );
|
|
}
|
|
|
|
#ifdef NST_MSVC_OPTIMIZE
|
|
#pragma optimize("", on)
|
|
#endif
|
|
|
|
class InOut::FileStream : public std::iostream
|
|
{
|
|
class Buffer : public Out::FileStream::Buffer
|
|
{
|
|
public:
|
|
|
|
explicit Buffer(const File& file)
|
|
: Out::FileStream::Buffer(file) {}
|
|
|
|
explicit Buffer(GenericString filename,uint flags)
|
|
: Out::FileStream::Buffer
|
|
(
|
|
*new Io::File
|
|
(
|
|
filename,
|
|
((flags & READ) ? Io::File::READ : 0) |
|
|
((flags & WRITE) ? Io::File::WRITE : 0) |
|
|
((flags & TRUNCATE) ? Io::File::EMPTY : 0)
|
|
),
|
|
true
|
|
)
|
|
{}
|
|
};
|
|
|
|
Buffer buffer;
|
|
|
|
public:
|
|
|
|
explicit FileStream(const File& file)
|
|
: std::iostream(&buffer), buffer(file) {}
|
|
|
|
explicit FileStream(GenericString filename,uint flags)
|
|
: std::iostream(&buffer), buffer(filename,flags) {}
|
|
};
|
|
|
|
InOut::InOut(const File& file)
|
|
: stream(*new FileStream(file))
|
|
{
|
|
}
|
|
|
|
InOut::InOut(GenericString filename,uint flags)
|
|
: stream(*new FileStream(filename,flags))
|
|
{
|
|
}
|
|
|
|
InOut::~InOut()
|
|
{
|
|
delete &stream;
|
|
}
|
|
|
|
InOut::operator std::istream& ()
|
|
{
|
|
return stream;
|
|
}
|
|
|
|
InOut::operator std::ostream& ()
|
|
{
|
|
return stream;
|
|
}
|
|
}
|
|
}
|
|
}
|