polserver/pol-core/pol/binaryfilescrobj.cpp
turleypol 90b92f4002
Get environment variable/Extended Testsuite (#359)
* added os:GetEnvironmentVariable to list all environs or get a single one

* first version of restarting the core to test save/load
added environment variable to filter tests

* fixed string constructor (size_t instead of signed int)

* added string_view constructor

* splitted and extended restart tests

* added docs

* added pol.cfg setting to disallow environment variable access

* Change environmental variable access rules
Instead of defaulting to all values allowed, now defaults to none. May
specify either `*` to allow all variables, or a comma-delimited list.

* Address review changes
- Use Clib lower instead of boost
- const auto references
- Separate tests for access and finding env vars

* Update documentation

* Apply suggestions from code review

Co-authored-by: Kevin Eady <8634912+KevinEady@users.noreply.github.com>
Co-authored-by: Fernando Rozenblit <rozenblit@gmail.com>
2021-02-27 08:36:22 +01:00

448 lines
11 KiB
C++

/** @file
*
* @par History
* - 2009/12/21 Turley: ._method() call fix
*/
#include "binaryfilescrobj.h"
#include <fstream>
#include <stddef.h>
#include "../bscript/berror.h"
#include "../bscript/bobject.h"
#include "../bscript/executor.h"
#include "../bscript/impstr.h"
#include "../bscript/objmembers.h"
#include "../bscript/objmethods.h"
#include "../clib/clib_endian.h"
#include "../clib/rawtypes.h"
namespace Pol
{
namespace Core
{
BBinaryfile::BBinaryfile()
: Bscript::BObjectImp( OTBinaryFile ),
_filename( "" ),
openmode( std::ios::in ),
bigendian( true )
{
}
BBinaryfile::BBinaryfile( std::string filename, unsigned short mode, bool _bigendian )
: Bscript::BObjectImp( OTBinaryFile ),
_filename( std::move( filename ) ),
bigendian( _bigendian )
{
using std::ios;
// FIXME: ms::stl has different flag values then stlport :(
openmode = static_cast<ios::openmode>( 0x0 );
if ( mode & 0x01 )
openmode |= ios::in;
if ( mode & 0x02 )
openmode |= ios::out;
if ( mode & 0x04 )
openmode |= ios::ate;
if ( mode & 0x08 )
openmode |= ios::app;
if ( mode & 0x10 )
openmode |= ios::trunc;
if ( !file.Open( _filename, openmode ) )
return;
}
BBinaryfile::~BBinaryfile()
{
file.Close();
}
size_t BBinaryfile::sizeEstimate() const
{
return sizeof( *this ) + _filename.capacity();
}
Bscript::BObjectRef BBinaryfile::get_member_id( const int /*id*/ ) // id test
{
return Bscript::BObjectRef( new Bscript::BLong( 0 ) );
}
Bscript::BObjectRef BBinaryfile::get_member( const char* membername )
{
Bscript::ObjMember* objmember = Bscript::getKnownObjMember( membername );
if ( objmember != nullptr )
return this->get_member_id( objmember->id );
else
return Bscript::BObjectRef( Bscript::UninitObject::create() );
}
Bscript::BObjectImp* BBinaryfile::call_method( const char* methodname, Bscript::Executor& ex )
{
Bscript::ObjMethod* objmethod = Bscript::getKnownObjMethod( methodname );
if ( objmethod != nullptr )
return this->call_method_id( objmethod->id, ex );
else
return nullptr;
}
Bscript::BObjectImp* BBinaryfile::call_method_id( const int id, Bscript::Executor& ex,
bool /*forcebuiltin*/ )
{
using namespace Bscript;
switch ( id )
{
case MTH_CLOSE:
file.Close();
return new BLong( 1 );
case MTH_SIZE:
return new BLong( static_cast<int>( file.FileSize( ex ) ) );
case MTH_SEEK:
{
using std::ios;
if ( ex.numParams() != 2 )
return new BError( "Seek requires 2 parameter." );
int value, type;
if ( ( !ex.getParam( 0, value ) ) || ( !ex.getParam( 1, type ) ) )
return new BError( "Invalid parameter" );
// FIXME: ms::stl has different flag values then stlport :(
ios::seekdir seekdir;
if ( type & 0x01 )
seekdir = ios::cur;
else if ( type & 0x02 )
seekdir = ios::end;
else
seekdir = ios::beg;
if ( !file.Seek( value, seekdir ) )
return new BLong( 0 );
return new BLong( 1 );
}
case MTH_TELL:
return new BLong( static_cast<int>( file.Tell() ) );
case MTH_PEEK:
return new BLong( file.Peek() );
case MTH_FLUSH:
file.Flush();
return new BLong( 1 );
case MTH_GETINT32:
{
u32 _u32;
if ( !file.Read( _u32 ) )
return new BError( "Failed to read" );
if ( bigendian )
_u32 = cfBEu32( _u32 );
return new BLong( _u32 );
}
case MTH_GETSINT32:
{
s32 _s32;
if ( !file.Read( _s32 ) )
return new BError( "Failed to read" );
if ( bigendian )
_s32 = cfBEu32( _s32 );
return new BLong( _s32 );
}
case MTH_GETINT16:
{
u16 _u16;
if ( !file.Read( _u16 ) )
return new BError( "Failed to read" );
if ( bigendian )
_u16 = cfBEu16( _u16 );
return new BLong( _u16 );
}
case MTH_GETSINT16:
{
s16 _s16;
if ( !file.Read( _s16 ) )
return new BError( "Failed to read" );
if ( bigendian )
_s16 = cfBEu16( _s16 );
return new BLong( _s16 );
}
case MTH_GETINT8:
{
u8 _u8;
if ( !file.Read( _u8 ) )
return new BError( "Failed to read" );
return new BLong( _u8 );
}
case MTH_GETSINT8:
{
s8 _s8;
if ( !file.Read( _s8 ) )
return new BError( "Failed to read" );
return new BLong( _s8 );
}
case MTH_GETSTRING:
{
if ( ex.numParams() != 1 )
return new BError( "GetString requires 1 parameter." );
int value;
if ( !ex.getParam( 0, value ) )
return new BError( "Invalid parameter" );
if ( value < 1 )
return new BError( "Len is negative or 0." );
std::vector<unsigned char> _char;
_char.resize( value );
if ( !file.Read( &_char[0], value ) )
return new BError( "Failed to read" );
size_t len = 0;
const char* _str = reinterpret_cast<const char*>( &_char[0] );
// Returns maximum of len characters or up to the first null-byte
while ( len < static_cast<size_t>( value ) && *( _str + len ) )
++len;
return new String( _str, len, String::Tainted::YES );
}
case MTH_SETINT32:
{
if ( ex.numParams() != 1 )
return new BError( "SetInt32 requires 1 parameter." );
int value;
if ( !ex.getParam( 0, value ) )
return new BError( "Invalid parameter" );
u32 _u32 = static_cast<u32>( value );
if ( bigendian )
_u32 = cfBEu32( _u32 );
if ( !file.Write( _u32 ) )
return new BError( "Failed to write" );
return new BLong( 1 );
}
case MTH_SETSINT32:
{
if ( ex.numParams() != 1 )
return new BError( "SetSInt32 requires 1 parameter." );
int value;
if ( !ex.getParam( 0, value ) )
return new BError( "Invalid parameter" );
s32 _s32 = static_cast<s32>( value );
if ( bigendian )
_s32 = cfBEu32( _s32 );
if ( !file.Write( _s32 ) )
return new BError( "Failed to write" );
return new BLong( 1 );
}
case MTH_SETINT16:
{
if ( ex.numParams() != 1 )
return new BError( "SetInt16 requires 1 parameter." );
int value;
if ( !ex.getParam( 0, value ) )
return new BError( "Invalid parameter" );
u16 _u16 = static_cast<u16>( value );
if ( bigendian )
_u16 = cfBEu16( _u16 );
if ( !file.Write( _u16 ) )
return new BError( "Failed to write" );
return new BLong( 1 );
}
case MTH_SETSINT16:
{
if ( ex.numParams() != 1 )
return new BError( "SetSInt16 requires 1 parameter." );
int value;
if ( !ex.getParam( 0, value ) )
return new BError( "Invalid parameter" );
s16 _s16 = static_cast<s16>( value );
if ( bigendian )
_s16 = cfBEu16( _s16 );
if ( !file.Write( _s16 ) )
return new BError( "Failed to write" );
return new BLong( 1 );
}
case MTH_SETINT8:
{
if ( ex.numParams() != 1 )
return new BError( "SetInt8 requires 1 parameter." );
int value;
if ( !ex.getParam( 0, value ) )
return new BError( "Invalid parameter" );
u8 _u8 = static_cast<u8>( value );
if ( !file.Write( _u8 ) )
return new BError( "Failed to write" );
return new BLong( 1 );
}
case MTH_SETSINT8:
{
if ( ex.numParams() != 1 )
return new BError( "SetSInt8 requires 1 parameter." );
int value;
if ( !ex.getParam( 0, value ) )
return new BError( "Invalid parameter" );
s8 _s8 = static_cast<s8>( value );
if ( !file.Write( _s8 ) )
return new BError( "Failed to write" );
return new BLong( 1 );
}
case MTH_SETSTRING:
{
if ( ex.numParams() != 2 )
return new BError( "SetString requires 2 parameters." );
int value;
const String* text;
if ( ( !ex.getStringParam( 0, text ) ) || ( !ex.getParam( 1, value ) ) )
return new BError( "Invalid parameter" );
u32 len = static_cast<u32>( text->value().length() );
if ( value == 1 )
len++;
if ( !file.WriteString( text->value().c_str(), len ) )
return new BError( "Failed to write" );
return new BLong( 1 );
}
default:
return nullptr;
}
}
Bscript::BObjectImp* BBinaryfile::copy() const
{
return new BBinaryfile( _filename, static_cast<unsigned short>( openmode ), bigendian );
}
std::string BBinaryfile::getStringRep() const
{
return "BinaryFile";
}
bool BBinaryfile::isTrue() const
{
if ( _filename == "" )
return false;
return file.IsOpen();
}
bool BBinaryfile::operator==( const Bscript::BObjectImp& objimp ) const
{
if ( objimp.isa( Bscript::BObjectImp::OTBinaryFile ) )
{
if ( ( (BBinaryfile&)objimp )._filename == _filename )
return true;
}
else if ( objimp.isa( Bscript::BObjectImp::OTBoolean ) )
return isTrue() == static_cast<const Bscript::BBoolean&>( objimp ).isTrue();
return false;
}
BinFile::BinFile( const std::string& filename, std::ios::openmode mode )
{
Open( filename, mode );
}
BinFile::~BinFile()
{
Close();
}
bool BinFile::Open( const std::string& filename, std::ios::openmode mode )
{
if ( _file.is_open() )
return true;
_file.open( filename.c_str(), mode | std::ios::binary );
if ( !_file.is_open() )
return false;
return true;
}
bool BinFile::IsOpen()
{
return _file.is_open();
}
void BinFile::Close()
{
if ( !_file.is_open() )
return;
_file.close();
}
bool BinFile::Seek( std::fstream::pos_type abs_offset, std::ios::seekdir origin )
{
if ( !_file.is_open() )
return false;
if ( !_file.seekg( abs_offset, origin ) )
return false;
return true;
}
bool BinFile::ReadBuffer( void* buffer, std::streamsize length )
{
if ( !_file.read( reinterpret_cast<char*>( buffer ), length ) )
return false;
return true;
}
bool BinFile::WriteBuffer( void* buffer, std::streamsize length )
{
if ( !_file.write( reinterpret_cast<char*>( buffer ), length ) )
return false;
return true;
}
bool BinFile::WriteString( const char* chr, unsigned len )
{
if ( !_file.write( chr, len ) )
return false;
return true;
}
std::fstream::pos_type BinFile::FileSize( Bscript::Executor& exec )
{
if ( !_file.is_open() )
return std::fstream::pos_type( 0 );
std::fstream::pos_type save_pos = _file.tellg();
if ( save_pos == std::fstream::pos_type( -1 ) )
{
exec.setFunctionResult(
new Bscript::BError( "FileSize failed to determine current position." ) );
return std::fstream::pos_type( 0 );
}
if ( !_file.seekg( 0, std::ios::end ) )
{
exec.setFunctionResult( new Bscript::BError( "FileSize failed to seek to end of file." ) );
return std::fstream::pos_type( 0 );
}
std::fstream::pos_type size = _file.tellg();
if ( size == std::fstream::pos_type( -1 ) )
{
exec.setFunctionResult( new Bscript::BError( "FileSize could not determine file size." ) );
return std::fstream::pos_type( 0 );
}
if ( !_file.seekg( save_pos ) )
{
exec.setFunctionResult(
new Bscript::BError( "FileSize failed to seek to original position." ) );
return std::fstream::pos_type( 0 );
}
return size;
}
std::fstream::pos_type BinFile::Tell()
{
if ( !_file.is_open() )
return -1;
return _file.tellg();
}
int BinFile::Peek()
{
if ( !_file.is_open() )
return -1;
return _file.peek();
}
void BinFile::Flush()
{
if ( _file.is_open() )
_file.flush();
}
} // namespace Core
} // namespace Pol