|
|
|
@ -24,79 +24,110 @@
|
|
|
|
|
#include <simgear/compiler.h>
|
|
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
# include <io.h>
|
|
|
|
|
#else
|
|
|
|
|
# include <sys/mman.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
|
|
#if !defined(_MSC_VER)
|
|
|
|
|
# include <unistd.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <simgear/misc/sg_path.hxx>
|
|
|
|
|
#include <simgear/misc/stdint.hxx>
|
|
|
|
|
#include <simgear/debug/logstream.hxx>
|
|
|
|
|
#include <simgear/misc/strutils.hxx>
|
|
|
|
|
|
|
|
|
|
#include "sg_mmap.hxx"
|
|
|
|
|
|
|
|
|
|
#if defined(SG_WINDOWS)
|
|
|
|
|
# define WIN32_LEAN_AND_MEAN
|
|
|
|
|
# include <windows.h>
|
|
|
|
|
# include <io.h>
|
|
|
|
|
#else
|
|
|
|
|
# include <sys/mman.h>
|
|
|
|
|
# include <unistd.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
class SGMMapFile::SGMMapFilePrivate
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
SGPath file_name;
|
|
|
|
|
int fp = -1;
|
|
|
|
|
bool eof_flag = true;
|
|
|
|
|
// Number of repetitions to play. -1 means loop infinitely.
|
|
|
|
|
int repeat = 1;
|
|
|
|
|
int iteration = 0; // number of current repetition,
|
|
|
|
|
// starting at 0
|
|
|
|
|
int extraoflags = 0;
|
|
|
|
|
|
|
|
|
|
char *buffer = nullptr;
|
|
|
|
|
off_t offset = 0;
|
|
|
|
|
size_t size = 0;
|
|
|
|
|
#if defined(SG_WINDOWS)
|
|
|
|
|
HANDLE _nativeHandle = NULL;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
ssize_t mmap_read(void *buf, size_t count);
|
|
|
|
|
ssize_t mmap_write(const void *buf, size_t count);
|
|
|
|
|
|
|
|
|
|
off_t forward(off_t amount);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
SGMMapFile::SGMMapFile( )
|
|
|
|
|
{
|
|
|
|
|
set_type( sgFileType );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SGMMapFile::SGMMapFile(const SGPath &file, int repeat_, int extraoflags_ )
|
|
|
|
|
: file_name(file), repeat(repeat_), extraoflags(extraoflags_)
|
|
|
|
|
: d(new SGMMapFilePrivate)
|
|
|
|
|
{
|
|
|
|
|
d->file_name = file;
|
|
|
|
|
d->repeat = repeat_;
|
|
|
|
|
d->extraoflags = extraoflags_;
|
|
|
|
|
set_type( sgFileType );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SGMMapFile::SGMMapFile( int existingFd ) :
|
|
|
|
|
fp(existingFd)
|
|
|
|
|
SGMMapFile::SGMMapFile( int existingFd )
|
|
|
|
|
: d(new SGMMapFilePrivate)
|
|
|
|
|
{
|
|
|
|
|
d->fp = existingFd;
|
|
|
|
|
set_type( sgFileType );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SGMMapFile::~SGMMapFile() {
|
|
|
|
|
SGMMapFile::~SGMMapFile()
|
|
|
|
|
{
|
|
|
|
|
close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// open the file based on specified direction
|
|
|
|
|
bool SGMMapFile::open( const SGPath& file, const SGProtocolDir d ) {
|
|
|
|
|
file_name = file;
|
|
|
|
|
return open(d);
|
|
|
|
|
bool SGMMapFile::open( const SGPath& file, const SGProtocolDir dir )
|
|
|
|
|
{
|
|
|
|
|
d->file_name = file;
|
|
|
|
|
return open(dir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// open the file based on specified direction
|
|
|
|
|
bool SGMMapFile::open( const SGProtocolDir d ) {
|
|
|
|
|
set_dir( d );
|
|
|
|
|
bool SGMMapFile::open( const SGProtocolDir dir )
|
|
|
|
|
{
|
|
|
|
|
set_dir( dir );
|
|
|
|
|
|
|
|
|
|
#if defined(SG_WINDOWS)
|
|
|
|
|
std::wstring n = file_name.wstr();
|
|
|
|
|
const std::wstring n = d->file_name.wstr();
|
|
|
|
|
#else
|
|
|
|
|
std::string n = file_name.utf8Str();
|
|
|
|
|
const std::string n = d->file_name.utf8Str();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( get_dir() == SG_IO_OUT ) {
|
|
|
|
|
#if defined(SG_WINDOWS)
|
|
|
|
|
int mode = _S_IREAD | _S_IWRITE;
|
|
|
|
|
fp = ::_wopen(n.c_str(), O_WRONLY | O_CREAT | O_TRUNC | extraoflags, mode);
|
|
|
|
|
d->fp = ::_wopen(n.c_str(), O_WRONLY | O_CREAT | O_TRUNC | d->extraoflags, mode);
|
|
|
|
|
#else
|
|
|
|
|
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
|
|
|
|
|
fp = ::open( n.c_str(), O_WRONLY | O_CREAT | O_TRUNC | extraoflags, mode );
|
|
|
|
|
d->fp = ::open( n.c_str(), O_WRONLY | O_CREAT | O_TRUNC | d->extraoflags, mode );
|
|
|
|
|
#endif
|
|
|
|
|
} else if ( get_dir() == SG_IO_IN ) {
|
|
|
|
|
#if defined(SG_WINDOWS)
|
|
|
|
|
fp = ::_wopen( n.c_str(), O_RDONLY | extraoflags );
|
|
|
|
|
d->fp = ::_wopen( n.c_str(), O_RDONLY | d->extraoflags );
|
|
|
|
|
#else
|
|
|
|
|
fp = ::open( n.c_str(), O_RDONLY | extraoflags );
|
|
|
|
|
d->fp = ::open( n.c_str(), O_RDONLY | d->extraoflags );
|
|
|
|
|
#endif
|
|
|
|
|
} else {
|
|
|
|
|
SG_LOG( SG_IO, SG_ALERT,
|
|
|
|
@ -104,30 +135,54 @@ bool SGMMapFile::open( const SGProtocolDir d ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( fp == -1 ) {
|
|
|
|
|
SG_LOG( SG_IO, SG_ALERT, "Error opening file: " << file_name );
|
|
|
|
|
if ( d->fp == -1 ) {
|
|
|
|
|
SG_LOG( SG_IO, SG_ALERT, "Error opening file: " << d->file_name
|
|
|
|
|
<< "\n\t" << simgear::strutils::error_string(errno));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// mmap
|
|
|
|
|
struct stat statbuf;
|
|
|
|
|
fstat(fp, &statbuf);
|
|
|
|
|
fstat(d->fp, &statbuf);
|
|
|
|
|
|
|
|
|
|
size = (size_t)statbuf.st_size;
|
|
|
|
|
buffer = (char*)simple_mmap(fp, size, &un);
|
|
|
|
|
if (buffer == (char*)-1)
|
|
|
|
|
{
|
|
|
|
|
SG_LOG( SG_IO, SG_ALERT, "Error mmapping file: " << file_name );
|
|
|
|
|
d->size = (size_t) statbuf.st_size;
|
|
|
|
|
#if defined(SG_WINDOWS)
|
|
|
|
|
HANDLE osfHandle = (HANDLE)_get_osfhandle(d->fp);
|
|
|
|
|
if (!osfHandle) {
|
|
|
|
|
SG_LOG( SG_IO, SG_ALERT, "Error mmapping file: _get_osfhandle failed:" << d->file_name
|
|
|
|
|
<< "\n\t" << simgear::strutils::error_string(errno));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
eof_flag = false;
|
|
|
|
|
d->_nativeHandle = CreateFileMapping(osfHandle, NULL, PAGE_READONLY, 0, 0, NULL);
|
|
|
|
|
if (!d->_nativeHandle) {
|
|
|
|
|
SG_LOG( SG_IO, SG_ALERT, "Error mmapping file: CreateFileMapping failed:" << d->file_name
|
|
|
|
|
<< "\n\t" << simgear::strutils::error_string(errno));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
d->buffer = reinterpret_cast<char*>(MapViewOfFile(d->_nativeHandle, FILE_MAP_READ, 0, 0, 0));
|
|
|
|
|
if (!d->buffer) {
|
|
|
|
|
CloseHandle(d->_nativeHandle);
|
|
|
|
|
SG_LOG( SG_IO, SG_ALERT, "Error mmapping file: MapViewOfFile failed:" << d->file_name
|
|
|
|
|
<< "\n\t" << simgear::strutils::error_string(errno));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
d->buffer = (char*) mmap(0, d->size, PROT_READ, MAP_PRIVATE, d->fp, 0L);
|
|
|
|
|
if (d->buffer == MAP_FAILED) {
|
|
|
|
|
SG_LOG( SG_IO, SG_ALERT, "Error mmapping file: " << d->file_name
|
|
|
|
|
<< "\n\t" << simgear::strutils::error_string(errno));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
d-> eof_flag = false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
off_t SGMMapFile::forward(off_t amount) {
|
|
|
|
|
if ((size_t)amount > size - offset) {
|
|
|
|
|
off_t SGMMapFile::SGMMapFilePrivate::forward(off_t amount)
|
|
|
|
|
{
|
|
|
|
|
if ((size_t) amount > size - offset) {
|
|
|
|
|
amount = size - offset;
|
|
|
|
|
}
|
|
|
|
|
offset += amount;
|
|
|
|
@ -138,78 +193,80 @@ off_t SGMMapFile::forward(off_t amount) {
|
|
|
|
|
return amount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* SGMMapFile::advance(off_t amount) {
|
|
|
|
|
const char *ptr = buffer + offset;
|
|
|
|
|
const char* SGMMapFile::advance(off_t amount)
|
|
|
|
|
{
|
|
|
|
|
const char *ptr = d->buffer + d->offset;
|
|
|
|
|
|
|
|
|
|
off_t advanced = forward(amount);
|
|
|
|
|
off_t advanced = d->forward(amount);
|
|
|
|
|
if (advanced != amount) {
|
|
|
|
|
eof_flag = true;
|
|
|
|
|
d->eof_flag = true;
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ssize_t SGMMapFile::mmap_read(void *buf, size_t count) {
|
|
|
|
|
ssize_t SGMMapFile::SGMMapFilePrivate::mmap_read(void *buf, size_t count)
|
|
|
|
|
{
|
|
|
|
|
const char *ptr = buffer + offset;
|
|
|
|
|
size_t result = forward(count);
|
|
|
|
|
|
|
|
|
|
memcpy(buf, ptr, result);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ssize_t SGMMapFile::mmap_write(const void *buf, size_t count) {
|
|
|
|
|
ssize_t SGMMapFile::SGMMapFilePrivate::mmap_write(const void *buf, size_t count)
|
|
|
|
|
{
|
|
|
|
|
char *ptr = buffer + offset;
|
|
|
|
|
size_t result = forward(count);
|
|
|
|
|
|
|
|
|
|
memcpy(ptr, buf, result);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// read a block of data of specified size
|
|
|
|
|
int SGMMapFile::read( char *buf, int length ) {
|
|
|
|
|
int SGMMapFile::read( char *buf, int length )
|
|
|
|
|
{
|
|
|
|
|
// read a chunk
|
|
|
|
|
ssize_t result = mmap_read(buf, length);
|
|
|
|
|
ssize_t result = d->mmap_read(buf, length);
|
|
|
|
|
if ( length > 0 && result == 0 ) {
|
|
|
|
|
if (repeat < 0 || iteration < repeat - 1) {
|
|
|
|
|
iteration++;
|
|
|
|
|
if (d->repeat < 0 || d->iteration < d->repeat - 1) {
|
|
|
|
|
d->iteration++;
|
|
|
|
|
// loop reading the file, unless it is empty
|
|
|
|
|
off_t fileLen = offset; // lseek(0, SEEK_CUR)
|
|
|
|
|
off_t fileLen = d->offset; // lseek(0, SEEK_CUR)
|
|
|
|
|
if (fileLen == 0) {
|
|
|
|
|
eof_flag = true;
|
|
|
|
|
d->eof_flag = true;
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
|
|
|
|
offset = 0; // lseek(0, SEEK_SET)
|
|
|
|
|
return mmap_read(buf, length);
|
|
|
|
|
d->offset = 0; // lseek(0, SEEK_SET)
|
|
|
|
|
return d->mmap_read(buf, length);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
eof_flag = true;
|
|
|
|
|
d->eof_flag = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SGMMapFile::read( char *buf, int length, int num ) {
|
|
|
|
|
return mmap_read(buf, num*length)/length;
|
|
|
|
|
int SGMMapFile::read( char *buf, int length, int num )
|
|
|
|
|
{
|
|
|
|
|
return d->mmap_read(buf, num*length)/length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// read a line of data, length is max size of input buffer
|
|
|
|
|
int SGMMapFile::readline( char *buf, int length ) {
|
|
|
|
|
int pos = offset; // pos = lseek(0, SEEK_CUR)
|
|
|
|
|
int SGMMapFile::readline( char *buf, int length )
|
|
|
|
|
{
|
|
|
|
|
int pos = d->offset; // pos = lseek(0, SEEK_CUR)
|
|
|
|
|
|
|
|
|
|
// read a chunk
|
|
|
|
|
ssize_t result = mmap_read(buf, length);
|
|
|
|
|
ssize_t result = d->mmap_read(buf, length);
|
|
|
|
|
if ( length > 0 && result == 0 ) {
|
|
|
|
|
if ((repeat < 0 || iteration < repeat - 1) && pos != 0) {
|
|
|
|
|
iteration++;
|
|
|
|
|
if ((d->repeat < 0 || d->iteration < d->repeat - 1) && pos != 0) {
|
|
|
|
|
d->iteration++;
|
|
|
|
|
|
|
|
|
|
pos = offset = 0; // pos = lseek(0, SEEK_SET)
|
|
|
|
|
result = mmap_read(buf, length);
|
|
|
|
|
pos = d->offset = 0; // pos = lseek(0, SEEK_SET)
|
|
|
|
|
result = d->mmap_read(buf, length);
|
|
|
|
|
} else {
|
|
|
|
|
eof_flag = true;
|
|
|
|
|
d->eof_flag = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -217,28 +274,30 @@ int SGMMapFile::readline( char *buf, int length ) {
|
|
|
|
|
int i;
|
|
|
|
|
for ( i = 0; i < result && buf[i] != '\n'; ++i );
|
|
|
|
|
if ( buf[i] == '\n' ) {
|
|
|
|
|
result = i + 1;
|
|
|
|
|
result = i + 1;
|
|
|
|
|
} else {
|
|
|
|
|
result = i;
|
|
|
|
|
result = i;
|
|
|
|
|
}
|
|
|
|
|
offset = pos + result; // lseek(pos+result, SEEK_SET)
|
|
|
|
|
d->offset = pos + result; // lseek(pos+result, SEEK_SET)
|
|
|
|
|
|
|
|
|
|
// just in case ...
|
|
|
|
|
buf[ result ] = '\0';
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string SGMMapFile::read_all() {
|
|
|
|
|
return std::string(buffer, size);
|
|
|
|
|
std::string SGMMapFile::read_all()
|
|
|
|
|
{
|
|
|
|
|
return std::string(d->buffer, d->size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// write data to a file
|
|
|
|
|
int SGMMapFile::write( const char *buf, const int length ) {
|
|
|
|
|
int result = mmap_write(buf, length);
|
|
|
|
|
int SGMMapFile::write( const char *buf, const int length )
|
|
|
|
|
{
|
|
|
|
|
int result = d->mmap_write(buf, length);
|
|
|
|
|
|
|
|
|
|
if ( result != length ) {
|
|
|
|
|
SG_LOG( SG_IO, SG_ALERT, "Error writing data: " << file_name );
|
|
|
|
|
SG_LOG( SG_IO, SG_ALERT, "Error writing data to mmaped-: " << d->file_name
|
|
|
|
|
<< "\n\t" << simgear::strutils::error_string(errno));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
@ -246,65 +305,60 @@ int SGMMapFile::write( const char *buf, const int length ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// write null terminated string to a file
|
|
|
|
|
int SGMMapFile::writestring( const char *str ) {
|
|
|
|
|
int SGMMapFile::writestring( const char *str )
|
|
|
|
|
{
|
|
|
|
|
int length = std::strlen( str );
|
|
|
|
|
return write( str, length );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// close the port
|
|
|
|
|
bool SGMMapFile::close() {
|
|
|
|
|
if (fp != -1 ) {
|
|
|
|
|
simple_unmmap(buffer, size, &un);
|
|
|
|
|
if ( ::close( fp ) == -1 ) {
|
|
|
|
|
bool SGMMapFile::close()
|
|
|
|
|
{
|
|
|
|
|
if (d->fp != -1 ) {
|
|
|
|
|
#if defined(SG_WINDOWS)
|
|
|
|
|
UnmapViewOfFile(d->buffer);
|
|
|
|
|
CloseHandle(d->_nativeHandle);
|
|
|
|
|
d->_nativeHandle = NULL;
|
|
|
|
|
#else
|
|
|
|
|
if (munmap(d->buffer, d->size) != 0) {
|
|
|
|
|
SG_LOG( SG_IO, SG_ALERT, "Error un-mapping mmaped-file: " << d->file_name
|
|
|
|
|
<< "\n\t" << simgear::strutils::error_string(errno));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
if ( ::close( d->fp ) == -1 ) {
|
|
|
|
|
SG_LOG( SG_IO, SG_ALERT, "Error clossing mmaped-file: " << d->file_name
|
|
|
|
|
<< "\n\t" << simgear::strutils::error_string(errno));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
eof_flag = true;
|
|
|
|
|
d->eof_flag = true;
|
|
|
|
|
d->fp = -1;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
|
/* Source:
|
|
|
|
|
* https://mollyrocket.com/forums/viewtopic.php?p=2529
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
|
SGMMapFile::simple_mmap(int fd, size_t length, SIMPLE_UNMMAP *un)
|
|
|
|
|
const char* SGMMapFile::get() const
|
|
|
|
|
{
|
|
|
|
|
HANDLE f;
|
|
|
|
|
HANDLE m;
|
|
|
|
|
void *p;
|
|
|
|
|
|
|
|
|
|
f = (HANDLE)_get_osfhandle(fd);
|
|
|
|
|
if (!f) return (void *)-1;
|
|
|
|
|
|
|
|
|
|
m = CreateFileMapping(f, NULL, PAGE_READONLY, 0, 0, NULL);
|
|
|
|
|
if (!m) return (void *)-1;
|
|
|
|
|
|
|
|
|
|
p = MapViewOfFile(m, FILE_MAP_READ, 0, 0, 0);
|
|
|
|
|
if (!p)
|
|
|
|
|
{
|
|
|
|
|
CloseHandle(m);
|
|
|
|
|
return (void *)-1;
|
|
|
|
|
}
|
|
|
|
|
return d->buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (un)
|
|
|
|
|
{
|
|
|
|
|
un->m = m;
|
|
|
|
|
un->p = p;
|
|
|
|
|
}
|
|
|
|
|
const char* SGMMapFile::ptr() const
|
|
|
|
|
{
|
|
|
|
|
return d->buffer + d->offset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return p;
|
|
|
|
|
size_t SGMMapFile::get_size() const
|
|
|
|
|
{
|
|
|
|
|
return d->size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SGMMapFile::simple_unmmap(void *addr, size_t len, SIMPLE_UNMMAP *un)
|
|
|
|
|
bool SGMMapFile::eof() const
|
|
|
|
|
{
|
|
|
|
|
UnmapViewOfFile(un->p);
|
|
|
|
|
CloseHandle(un->m);
|
|
|
|
|
return d->eof_flag;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
off_t SGMMapFile::forward(off_t amount)
|
|
|
|
|
{
|
|
|
|
|
return d->forward(amount);
|
|
|
|
|
}
|
|
|
|
|