Add a cross-platform file mmap class and use it to access the timezone file, removing the need to keep the database in memory.
This commit is contained in:
325
simgear/io/sg_mmap.cxx
Normal file
325
simgear/io/sg_mmap.cxx
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
// sg_mmap.cxx -- File I/O routines
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started November 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program 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.
|
||||||
|
//
|
||||||
|
// This program 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 this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
#include <simgear_config.h>
|
||||||
|
#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/stdint.hxx>
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
|
#include "sg_mmap.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
/*
|
||||||
|
* map 'filename' and return a pointer to it.
|
||||||
|
*/
|
||||||
|
static void *simple_mmap(int, size_t, SIMPLE_UNMMAP *);
|
||||||
|
static void simple_unmmap(void*, size_t, SIMPLE_UNMMAP *);
|
||||||
|
#else
|
||||||
|
# define simple_mmap(a, b, c) mmap(0, (b), PROT_READ, MAP_PRIVATE, (a), 0L)
|
||||||
|
# define simple_unmmap(a, b, c) munmap((a), (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SGMMapFile::SGMMapFile( )
|
||||||
|
{
|
||||||
|
set_type( sgFileType );
|
||||||
|
}
|
||||||
|
|
||||||
|
SGMMapFile::SGMMapFile(const SGPath &file, int repeat_, int extraoflags_ )
|
||||||
|
: file_name(file), repeat(repeat_), extraoflags(extraoflags_)
|
||||||
|
{
|
||||||
|
set_type( sgFileType );
|
||||||
|
}
|
||||||
|
|
||||||
|
SGMMapFile::SGMMapFile( int existingFd ) :
|
||||||
|
fp(existingFd)
|
||||||
|
{
|
||||||
|
set_type( sgFileType );
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// open the file based on specified direction
|
||||||
|
bool SGMMapFile::open( const SGProtocolDir d ) {
|
||||||
|
set_dir( d );
|
||||||
|
|
||||||
|
#if defined(SG_WINDOWS)
|
||||||
|
std::wstring n = file_name.wstr();
|
||||||
|
#else
|
||||||
|
std::string n = 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);
|
||||||
|
#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 );
|
||||||
|
#endif
|
||||||
|
} else if ( get_dir() == SG_IO_IN ) {
|
||||||
|
#if defined(SG_WINDOWS)
|
||||||
|
fp = ::_wopen( n.c_str(), O_RDONLY | extraoflags );
|
||||||
|
#else
|
||||||
|
fp = ::open( n.c_str(), O_RDONLY | extraoflags );
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
SG_LOG( SG_IO, SG_ALERT,
|
||||||
|
"Error: bidirection mode not available for files." );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( fp == -1 ) {
|
||||||
|
SG_LOG( SG_IO, SG_ALERT, "Error opening file: " << file_name );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mmap
|
||||||
|
struct stat statbuf;
|
||||||
|
fstat(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 );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
eof_flag = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// read a block of data of specified size
|
||||||
|
int SGMMapFile::read( char *buf, int length ) {
|
||||||
|
size_t read_size = length;
|
||||||
|
size_t result = length;
|
||||||
|
size_t pos = offset;
|
||||||
|
|
||||||
|
if (read_size > size - offset) {
|
||||||
|
read_size = size - offset;
|
||||||
|
result = 0; // eof
|
||||||
|
}
|
||||||
|
|
||||||
|
// read a chunk
|
||||||
|
memcpy(buf, buffer+offset, read_size);
|
||||||
|
offset += read_size;
|
||||||
|
|
||||||
|
if ( length > 0 && result == 0 ) {
|
||||||
|
if (repeat < 0 || iteration < repeat - 1) {
|
||||||
|
iteration++;
|
||||||
|
// loop reading the file, unless it is empty
|
||||||
|
|
||||||
|
off_t fileLen = pos;
|
||||||
|
if (fileLen == 0) {
|
||||||
|
eof_flag = true;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
offset = 0;
|
||||||
|
if (read_size > size) {
|
||||||
|
read_size = size;
|
||||||
|
result = 0; // eof
|
||||||
|
}
|
||||||
|
memcpy(buf, buffer, read_size);
|
||||||
|
offset += read_size;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eof_flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// read a line of data, length is max size of input buffer
|
||||||
|
int SGMMapFile::readline( char *buf, int length ) {
|
||||||
|
size_t read_size = length;
|
||||||
|
size_t result = length;
|
||||||
|
size_t pos = offset;
|
||||||
|
|
||||||
|
if (read_size > size - offset) {
|
||||||
|
read_size = size - offset;
|
||||||
|
result = 0; // eof
|
||||||
|
}
|
||||||
|
|
||||||
|
// read a chunk
|
||||||
|
memcpy(buf, buffer+offset, read_size);
|
||||||
|
offset += read_size;
|
||||||
|
|
||||||
|
if ( length > 0 && result == 0 ) {
|
||||||
|
if ((repeat < 0 || iteration < repeat - 1) && pos != 0) {
|
||||||
|
iteration++;
|
||||||
|
|
||||||
|
pos = 0;
|
||||||
|
result = length;
|
||||||
|
read_size = length;
|
||||||
|
if (read_size > size) {
|
||||||
|
read_size = size;
|
||||||
|
result = 0; // eof
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buf, buffer, read_size);
|
||||||
|
offset += read_size;
|
||||||
|
} else {
|
||||||
|
eof_flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the end of line and reset position
|
||||||
|
size_t i;
|
||||||
|
for ( i = 0; i < result && buf[i] != '\n'; ++i );
|
||||||
|
if ( buf[i] == '\n' ) {
|
||||||
|
result = i + 1;
|
||||||
|
} else {
|
||||||
|
result = i;
|
||||||
|
}
|
||||||
|
offset = pos + result;
|
||||||
|
|
||||||
|
// just in case ...
|
||||||
|
buf[ result ] = '\0';
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SGMMapFile::read_all()
|
||||||
|
{
|
||||||
|
return std::string(buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write data to a file
|
||||||
|
int SGMMapFile::write( const char *buf, const int length ) {
|
||||||
|
size_t write_size = length;
|
||||||
|
|
||||||
|
if (write_size > size - offset) {
|
||||||
|
SG_LOG( SG_IO, SG_ALERT, "Attempting to write beyond the mmap buffer size: " << file_name );
|
||||||
|
write_size = size - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffer+offset, buf, write_size);
|
||||||
|
offset += write_size;
|
||||||
|
|
||||||
|
return write_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// write null terminated string to a file
|
||||||
|
int SGMMapFile::writestring( const char *str ) {
|
||||||
|
size_t write_size = std::strlen( str );
|
||||||
|
if (write_size > size - offset) {
|
||||||
|
SG_LOG( SG_IO, SG_ALERT, "Attempting to write beyond the mmap buffer size: " << file_name );
|
||||||
|
write_size = size - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffer+offset, str, write_size);
|
||||||
|
offset += write_size;
|
||||||
|
|
||||||
|
return write_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// close the port
|
||||||
|
bool SGMMapFile::close() {
|
||||||
|
if (fp != -1 ) {
|
||||||
|
simple_unmmap(buffer, size, &un);
|
||||||
|
if ( ::close( fp ) == -1 ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
eof_flag = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
/* Source:
|
||||||
|
* https://mollyrocket.com/forums/viewtopic.php?p=2529
|
||||||
|
*/
|
||||||
|
|
||||||
|
void *
|
||||||
|
simple_mmap(int fd, size_t length, SIMPLE_UNMMAP *un)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (un)
|
||||||
|
{
|
||||||
|
un->m = m;
|
||||||
|
un->p = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
simple_unmmap(void *addr, size_t len, SIMPLE_UNMMAP *un)
|
||||||
|
{
|
||||||
|
UnmapViewOfFile(un->p);
|
||||||
|
CloseHandle(un->m);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
122
simgear/io/sg_mmap.hxx
Normal file
122
simgear/io/sg_mmap.hxx
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
///@mmap
|
||||||
|
/// File I/O routines.
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started November 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library 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
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Library General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
#ifndef _SG_MMAP_HXX
|
||||||
|
#define _SG_MMAP_HXX
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
|
||||||
|
#include "iochannel.hxx"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A file I/O class based on SGIOChannel.
|
||||||
|
*/
|
||||||
|
class SGMMapFile : public SGIOChannel {
|
||||||
|
|
||||||
|
SGPath file_name;
|
||||||
|
int fp = -1;
|
||||||
|
bool eof_flag = true;
|
||||||
|
// Number of repetitions to play. -1 means loop infinitely.
|
||||||
|
const int repeat = 1;
|
||||||
|
int iteration = 0; // number of current repetition,
|
||||||
|
// starting at 0
|
||||||
|
int extraoflags = 0;
|
||||||
|
|
||||||
|
char *buffer = nullptr;
|
||||||
|
size_t offset = 0;
|
||||||
|
size_t size = 0;
|
||||||
|
#ifdef WIN32
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
HANDLE m;
|
||||||
|
void *p;
|
||||||
|
} SIMPLE_UNMMAP;
|
||||||
|
SIMPLE_UNMMAP un;
|
||||||
|
#else
|
||||||
|
int un; // referenced but not used
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
SGMMapFile();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create an instance of SGMMapFile.
|
||||||
|
* When calling the constructor you need to provide a file
|
||||||
|
* name. This file is not opened immediately, but instead will be
|
||||||
|
* opened when the open() method is called.
|
||||||
|
* @param file name of file to open
|
||||||
|
* @param repeat On eof restart at the beginning of the file
|
||||||
|
*/
|
||||||
|
SGMMapFile( const SGPath& file, int repeat_ = 1, int extraoflags = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an SGMMapFile from an existing, open file-descriptor
|
||||||
|
*/
|
||||||
|
SGMMapFile( int existingFd );
|
||||||
|
|
||||||
|
/** Destructor */
|
||||||
|
virtual ~SGMMapFile();
|
||||||
|
|
||||||
|
// open the file based on specified direction
|
||||||
|
bool open( const SGPath& file, const SGProtocolDir dir );
|
||||||
|
bool open( const SGProtocolDir dir );
|
||||||
|
|
||||||
|
// read a block of data of specified size
|
||||||
|
int read( char *buf, int length );
|
||||||
|
|
||||||
|
// read a line of data, length is max size of input buffer
|
||||||
|
int readline( char *buf, int length );
|
||||||
|
|
||||||
|
// reads the whole file into a buffer
|
||||||
|
// note: this really defeats the purpose of mmapping a file
|
||||||
|
std::string read_all();
|
||||||
|
|
||||||
|
inline const char* get() { return buffer; }
|
||||||
|
|
||||||
|
inline size_t get_size() { return size; }
|
||||||
|
|
||||||
|
// write data to a file
|
||||||
|
int write( const char *buf, const int length );
|
||||||
|
|
||||||
|
// write null terminated string to a file
|
||||||
|
int writestring( const char *str );
|
||||||
|
|
||||||
|
// close file
|
||||||
|
bool close();
|
||||||
|
|
||||||
|
/** @return the name of the file being manipulated. */
|
||||||
|
std::string get_file_name() const { return file_name.utf8Str(); }
|
||||||
|
|
||||||
|
/** @return true of eof conditions exists */
|
||||||
|
virtual bool eof() const { return eof_flag; };
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _SG_MMAP_HXX
|
||||||
Reference in New Issue
Block a user