Changing SGPath APIs, using SGPath in more places.

Change most places we control (i.e not helper libs) to use SGPath
to represent a path, instead of using std::string. Extend SGPath
API to explicitly expose the path in either UTF-8 or the
system 8-bit encoding.
This commit is contained in:
James Turner
2016-06-20 16:38:47 +01:00
parent 855ff5a8b0
commit bd896096cc
20 changed files with 210 additions and 84 deletions

View File

@@ -14,6 +14,7 @@
#include "sg_binobj.hxx"
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sg_path.hxx>
using std::cout;
using std::endl;
@@ -31,7 +32,7 @@ int main( int argc, char **argv ) {
sglog().setLogLevels( SG_ALL, SG_ALERT );
SGBinObject obj;
bool result = obj.read_bin( argv[1] );
bool result = obj.read_bin( SGPath::fromLocal8Bit(argv[1]) );
if ( !result ) {
cout << "error loading: " << argv[1] << endl;
exit(-1);

View File

@@ -83,7 +83,7 @@ int main(int argc, char* argv[])
} else if (!strcmp(argv[a], "--auth")) {
proxyAuth = argv[++a];
} else if (!strcmp(argv[a], "-f") || !strcmp(argv[a], "--file")) {
outFile = new SGFile(argv[++a]);
outFile = new SGFile(SGPath::fromLocal8Bit(argv[++a]));
if (!outFile->open(SG_IO_OUT)) {
cerr << "failed to open output for writing:" << outFile->get_file_name() << endl;
return EXIT_FAILURE;

View File

@@ -491,7 +491,7 @@ void SGBinObject::read_object( gzFile fp,
// read a binary file and populate the provided structures.
bool SGBinObject::read_bin( const string& file ) {
bool SGBinObject::read_bin( const SGPath& file ) {
SGVec3d p;
int i, k;
size_t j;
@@ -535,13 +535,14 @@ bool SGBinObject::read_bin( const string& file ) {
fan_materials.clear();
gzFile fp;
if ( (fp = gzopen( file.c_str(), "rb" )) == NULL ) {
string filegz = file + ".gz";
string f = file.local8BitStr();
if ( (fp = gzopen( f.c_str(), "rb" )) == NULL ) {
string filegz = f + ".gz";
if ( (fp = gzopen( filegz.c_str(), "rb" )) == NULL ) {
SG_LOG( SG_EVENT, SG_ALERT,
"ERROR: opening " << file << " or " << filegz << " for reading!");
throw sg_io_exception("Error opening for reading (and .gz)", sg_location(file));
throw sg_io_exception("Error opening for reading (and .gz)", sg_location(f));
}
}
@@ -958,7 +959,7 @@ bool SGBinObject::write_bin_file(const SGPath& file)
gzFile fp;
if ( (fp = gzopen( file.c_str(), "wb9" )) == NULL ) {
cout << "ERROR: opening " << file.str() << " for writing!" << endl;
cout << "ERROR: opening " << file << " for writing!" << endl;
return false;
}
@@ -1064,7 +1065,7 @@ bool SGBinObject::write_bin_file(const SGPath& file)
gzclose(fp);
if ( sgWriteError() ) {
cout << "Error while writing file " << file.str() << endl;
cout << "Error while writing file " << file << endl;
return false;
}
@@ -1082,11 +1083,11 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
SGPath file = base + "/" + b.gen_base_path() + "/" + name;
file.create_dir( 0755 );
cout << "Output file = " << file.str() << endl;
cout << "Output file = " << file << endl;
FILE *fp;
if ( (fp = fopen( file.c_str(), "w" )) == NULL ) {
cout << "ERROR: opening " << file.str() << " for writing!" << endl;
cout << "ERROR: opening " << file << " for writing!" << endl;
return false;
}
@@ -1240,11 +1241,11 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
// close the file
fclose(fp);
string command = "gzip --force --best " + file.str();
string command = "gzip --force --best " + file.local8BitStr();
int err = system(command.c_str());
if (err)
{
cout << "ERROR: gzip " << file.str() << " failed!" << endl;
cout << "ERROR: gzip " << file << " failed!" << endl;
}
return (err == 0);

View File

@@ -268,7 +268,7 @@ public:
* @param file input file name
* @return result of read
*/
bool read_bin( const std::string& file );
bool read_bin( const SGPath& file );
/**
* Write out the structures to a binary file. We assume that the

View File

@@ -45,7 +45,7 @@
#include "sg_file.hxx"
SGFile::SGFile(const std::string &file, int repeat_, int extraoflags_ )
SGFile::SGFile(const SGPath &file, int repeat_, int extraoflags_ )
: file_name(file), fp(-1), eof_flag(true), repeat(repeat_), iteration(0),
extraoflags(extraoflags_)
{
@@ -69,24 +69,25 @@ SGFile::~SGFile() {
bool SGFile::open( const SGProtocolDir d ) {
set_dir( d );
std::string n = file_name.local8BitStr();
if ( get_dir() == SG_IO_OUT ) {
#ifdef _WIN32
int mode = _S_IREAD | _S_IWRITE;
#else
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
#endif
fp = ::open( file_name.c_str(), O_WRONLY | O_CREAT | O_TRUNC | extraoflags, mode );
fp = ::open( n.c_str(), O_WRONLY | O_CREAT | O_TRUNC | extraoflags, mode );
} else if ( get_dir() == SG_IO_IN ) {
fp = ::open( file_name.c_str(), O_RDONLY | extraoflags );
fp = ::open( n.c_str(), O_RDONLY | extraoflags );
} else {
SG_LOG( SG_IO, SG_ALERT,
"Error: bidirection mode not available for files." );
return false;
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;
SG_LOG( SG_IO, SG_ALERT, "Error opening file: " << file_name );
return false;
}
eof_flag = false;
@@ -180,7 +181,7 @@ bool SGFile::close() {
return true;
}
SGBinaryFile::SGBinaryFile( const std::string& file, int repeat_ ) :
SGBinaryFile::SGBinaryFile( const SGPath& file, int repeat_ ) :
#ifdef _WIN32
SGFile(file,repeat_, _O_BINARY)
#else

View File

@@ -23,6 +23,9 @@
#define _SG_FILE_HXX
#include <simgear/compiler.h>
#include <simgear/misc/sg_path.hxx>
#include "iochannel.hxx"
#include <string>
@@ -32,7 +35,7 @@
*/
class SGFile : public SGIOChannel {
std::string file_name;
SGPath file_name;
int fp;
bool eof_flag;
// Number of repetitions to play. -1 means loop infinitely.
@@ -51,7 +54,7 @@ public:
* @param file name of file to open
* @param repeat On eof restart at the beginning of the file
*/
SGFile( const std::string& file, int repeat_ = 1, int extraoflags = 0);
SGFile( const SGPath& file, int repeat_ = 1, int extraoflags = 0);
/**
* Create an SGFile from an existing, open file-descriptor
@@ -80,7 +83,7 @@ public:
bool close();
/** @return the name of the file being manipulated. */
inline std::string get_file_name() const { return file_name; }
std::string get_file_name() const { return file_name.utf8Str(); }
/** @return true of eof conditions exists */
virtual bool eof() const { return eof_flag; };
@@ -88,7 +91,7 @@ public:
class SGBinaryFile : public SGFile {
public:
SGBinaryFile( const std::string& file, int repeat_ = 1 );
SGBinaryFile( const SGPath& file, int repeat_ = 1 );
};
#endif // _SG_FILE_HXX

View File

@@ -32,6 +32,7 @@
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sgstream.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include "interpolater.hxx"
@@ -57,7 +58,7 @@ SGInterpTable::SGInterpTable( const std::string& file )
{
SG_LOG( SG_MATH, SG_INFO, "Initializing Interpolator for " << file );
sg_gzifstream in( file );
sg_gzifstream in( SGPath::fromUtf8(file) );
if ( !in.is_open() ) {
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
return;

View File

@@ -47,6 +47,7 @@
#include <simgear/props/props_io.hxx>
#include <simgear/misc/stdint.hxx>
#include <simgear/misc/sg_path.hxx>
#include <string.h>
@@ -139,7 +140,7 @@ gzContainerWriter::writeContainer(ContainerType Type, SGPropertyNode* root)
gzContainerReader::gzContainerReader(const std::string& name,
const std::string& fileMagic) :
sg_gzifstream(name, ios_in | ios_binary),
sg_gzifstream(SGPath(name), ios_in | ios_binary),
filename(name)
{
bool ok = (good() && !eof());

View File

@@ -222,6 +222,17 @@ SGPath::SGPath( const SGPath& p,
fix();
}
SGPath SGPath::fromLocal8Bit(const char *name)
{
return SGPath(simgear::strutils::convertWindowsLocal8BitToUtf8(name));
}
SGPath SGPath::fromUtf8(const std::string& bytes, PermissionChecker p)
{
return SGPath(bytes, p);
}
SGPath::SGPath(const SGPath& p) :
path(p.path),
_permission_checker(p._permission_checker),
@@ -330,6 +341,10 @@ void SGPath::concat( const string& p ) {
_rwCached = false;
}
std::string SGPath::local8BitStr() const
{
return simgear::strutils::convertUtf8ToWindowsLocal8Bit(path);
}
// Get the file part of the path (everything after the last path sep)
string SGPath::file() const
@@ -533,7 +548,7 @@ int SGPath::create_dir(mode_t mode)
if( !canWrite() )
{
SG_LOG( SG_IO,
SG_WARN, "Error creating directory for '" << str() << "'"
SG_WARN, "Error creating directory for '" << *this << "'"
" reason: access denied" );
return -3;
}
@@ -566,11 +581,11 @@ int SGPath::create_dir(mode_t mode)
if( sgMkDir(dir.c_str(), mode) )
{
SG_LOG( SG_IO,
SG_ALERT, "Error creating directory: (" << dir.str() << ")" );
SG_ALERT, "Error creating directory: (" << dir << ")" );
return -2;
}
else
SG_LOG(SG_IO, SG_DEBUG, "Directory created: " << dir.str());
SG_LOG(SG_IO, SG_DEBUG, "Directory created: " << dir);
if( i >= path_elements.size() )
return 0;
@@ -648,7 +663,7 @@ bool SGPath::isNull() const
std::string SGPath::str_native() const
{
#ifdef _WIN32
std::string s = str();
std::string s = local8BitStr();
std::string::size_type pos;
std::string nativeSeparator;
nativeSeparator = sgDirPathSepBad;
@@ -658,7 +673,7 @@ std::string SGPath::str_native() const
}
return s;
#else
return str();
return utf8Str();
#endif
}
@@ -667,7 +682,7 @@ bool SGPath::remove()
{
if( !canWrite() )
{
SG_LOG( SG_IO, SG_WARN, "file remove failed: (" << str() << ")"
SG_LOG( SG_IO, SG_WARN, "file remove failed: (" << *this << ")"
" reason: access denied" );
return false;
}
@@ -675,7 +690,7 @@ bool SGPath::remove()
int err = ::unlink(c_str());
if( err )
{
SG_LOG( SG_IO, SG_WARN, "file remove failed: (" << str() << ") "
SG_LOG( SG_IO, SG_WARN, "file remove failed: (" << *this << ") "
" reason: " << strerror(errno) );
// TODO check if failed unlink can really change any of the cached values
}
@@ -712,8 +727,8 @@ bool SGPath::rename(const SGPath& newName)
{
if( !canRead() || !canWrite() || !newName.canWrite() )
{
SG_LOG( SG_IO, SG_WARN, "rename failed: from " << str() <<
" to " << newName.str() <<
SG_LOG( SG_IO, SG_WARN, "rename failed: from " << *this <<
" to " << newName <<
" reason: access denied" );
return false;
}
@@ -726,10 +741,13 @@ bool SGPath::rename(const SGPath& newName)
}
}
#endif
if( ::rename(c_str(), newName.c_str()) != 0 )
std::string p = local8BitStr();
std::string np = newName.local8BitStr();
if( ::rename(p.c_str(), np.c_str()) != 0 )
{
SG_LOG( SG_IO, SG_WARN, "rename failed: from " << str() <<
" to " << newName.str() <<
SG_LOG( SG_IO, SG_WARN, "rename failed: from " << *this <<
" to " << newName <<
" reason: " << strerror(errno) );
return false;
}
@@ -821,6 +839,39 @@ SGPath SGPath::fromEnv(const char* name, const SGPath& def)
return def;
}
//------------------------------------------------------------------------------
std::vector<SGPath> SGPath::pathsFromEnv(const char *name)
{
std::vector<SGPath> r;
const char* val = getenv(name);
if (!val) {
return r;
}
string_list items = sgPathSplit(val);
string_list_iterator it;
for (it = items.begin(); it != items.end(); ++it) {
r.push_back(SGPath::fromLocal8Bit(it->c_str()));
}
return r;
}
//------------------------------------------------------------------------------
std::vector<SGPath> SGPath::pathsFromLocal8Bit(const std::string& paths)
{
std::vector<SGPath> r;
string_list items = sgPathSplit(paths);
string_list_iterator it;
for (it = items.begin(); it != items.end(); ++it) {
r.push_back(SGPath::fromLocal8Bit(it->c_str()));
}
return r;
}
//------------------------------------------------------------------------------
SGPath SGPath::home(const SGPath& def)
{
@@ -882,3 +933,22 @@ std::string SGPath::realpath() const
free(buf);
return p;
}
//------------------------------------------------------------------------------
std::string SGPath::join(const std::vector<SGPath>& paths, const std::string& joinWith)
{
std::string r;
if (paths.empty()) {
return r;
}
r = paths[0].utf8Str();
for (size_t i=1; i<paths.size(); ++i) {
r += joinWith + paths[i].utf8Str();
}
return r;
}

View File

@@ -186,6 +186,10 @@ public:
* @return path string
*/
std::string str() const { return path; }
std::string utf8Str() const { return path; }
std::string local8BitStr() const;
/**
* Get the path string
@@ -286,6 +290,10 @@ public:
*/
static SGPath fromEnv(const char* name, const SGPath& def = SGPath());
static SGPath fromUtf8(const std::string& bytes, PermissionChecker p = NULL);
static SGPath fromLocal8Bit(const char* name);
/**
* Get path to user's home directory
*/
@@ -301,6 +309,11 @@ public:
*/
static SGPath documents(const SGPath& def = SGPath());
static std::vector<SGPath> pathsFromEnv(const char* name);
static std::vector<SGPath> pathsFromLocal8Bit(const std::string& paths);
static std::string join(const std::vector<SGPath>& paths, const std::string& joinWith);
private:
void fix();
@@ -328,8 +341,7 @@ template<typename char_type, typename traits_type>
inline
std::basic_ostream<char_type, traits_type>&
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGPath& p)
{ return s << "Path \"" << p.str() << "\""; }
{ return s << "Path \"" << p.utf8Str() << "\""; }
/**
* Split a directory string into a list of it's parent directories.

View File

@@ -27,6 +27,8 @@
#include "sgstream.hxx"
#include <simgear/misc/sg_path.hxx>
using std::istream;
using std::ostream;
@@ -39,7 +41,7 @@ sg_gzifstream::sg_gzifstream()
//
// Open a possibly gzipped file for reading.
//
sg_gzifstream::sg_gzifstream( const std::string& name, ios_openmode io_mode )
sg_gzifstream::sg_gzifstream( const SGPath& name, ios_openmode io_mode )
: istream(&gzbuf)
{
this->open( name, io_mode );
@@ -64,26 +66,27 @@ sg_gzifstream::sg_gzifstream( int fd, ios_openmode io_mode )
// then append ".gz" and try again.
//
void
sg_gzifstream::open( const std::string& name, ios_openmode io_mode )
sg_gzifstream::open( const SGPath& name, ios_openmode io_mode )
{
gzbuf.open( name.c_str(), io_mode );
std::string s = name.local8BitStr();
gzbuf.open( s.c_str(), io_mode );
if ( ! gzbuf.is_open() )
{
std::string s = name;
if ( s.substr( s.length() - 3, 3 ) == ".gz" )
{
// remove ".gz" suffix
s.replace( s.length() - 3, 3, "" );
// s.erase( s.length() - 3, 3 );
}
else
{
// Append ".gz" suffix
s += ".gz";
}
if ( s.substr( s.length() - 3, 3 ) == ".gz" )
{
// remove ".gz" suffix
s.replace( s.length() - 3, 3, "" );
// s.erase( s.length() - 3, 3 );
}
else
{
// Append ".gz" suffix
s += ".gz";
}
// Try again.
gzbuf.open( s.c_str(), io_mode );
// Try again.
gzbuf.open( s.c_str(), io_mode );
}
}

View File

@@ -40,6 +40,8 @@
#include <simgear/misc/zfstream.hxx>
class SGPath;
/**
* An envelope class for gzifstream.
*/
@@ -55,7 +57,7 @@ public:
* @param name name of file
* @param io_mode file open mode(s) "or'd" together
*/
sg_gzifstream( const std::string& name,
sg_gzifstream( const SGPath& name,
ios_openmode io_mode = ios_in | ios_binary );
/**
@@ -70,7 +72,7 @@ public:
* @param name name of file
* @param io_mode file open mode(s) "or'd" together
*/
void open( const std::string& name,
void open( const SGPath& name,
ios_openmode io_mode = ios_in|ios_binary );
/**

View File

@@ -8,6 +8,7 @@ using std::cout;
using std::endl;
#include <simgear/misc/sgstream.hxx>
#include <simgear/misc/sg_path.hxx>
int main()
{
@@ -24,7 +25,8 @@ int main()
f.close();
}
sg_gzifstream sg(fileName);
SGPath p(fileName);
sg_gzifstream sg(p);
std::string stuff;
sg >> skipeol;
sg >> stuff;

View File

@@ -407,6 +407,27 @@ std::string convertWindowsLocal8BitToUtf8(const std::string& a)
#endif
}
std::string convertUtf8ToWindowsLocal8Bit(const std::string& a)
{
#ifdef SG_WINDOWS
DWORD flags = 0;
WCharVec wideString = convertMultiByteToWString(CP_UTF8, a);
// convert down to local multi-byte
std::vector<char> result;
int requiredChars = WideCharToMultiByte(CP_ACP, flags,
wideString.data(), wideString.size(),
NULL, 0, NULL, NULL);
result.resize(requiredChars);
WideCharToMultiByte(CP_ACP, flags,
wideString.data(), wideString.size(),
result.data(), result.size(), NULL, NULL);
return std::string(result.data(), result.size());
#else
return a;
#endif
}
//------------------------------------------------------------------------------
std::string md5(const unsigned char* data, size_t num)
{

View File

@@ -171,6 +171,11 @@ namespace simgear {
*/
std::string convertWindowsLocal8BitToUtf8(const std::string& a);
/**
*
*/
std::string convertUtf8ToWindowsLocal8Bit(const std::string& a);
#if defined(SG_WINDOWS)
typedef std::vector<wchar_t> WCharVec;
WCharVec convertUtf8ToWString(const std::string& a);

View File

@@ -191,7 +191,7 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
throw sg_io_exception(message, location,
"SimGear Property Reader");
}
readProperties(path.str(), _root, 0, _extended);
readProperties(path, _root, 0, _extended);
} catch (sg_io_exception &e) {
setException(e);
}
@@ -278,7 +278,7 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
message += val;
throw sg_io_exception(message, location, "SimGear Property Reader");
}
readProperties(path.str(), node, 0, _extended);
readProperties(path, node, 0, _extended);
}
catch (sg_io_exception &e)
{
@@ -434,11 +434,11 @@ readProperties (istream &input, SGPropertyNode * start_node,
* @return true if the read succeeded, false otherwise.
*/
void
readProperties (const string &file, SGPropertyNode * start_node,
readProperties (const SGPath &file, SGPropertyNode * start_node,
int default_mode, bool extended)
{
PropsVisitor visitor(start_node, file, default_mode, extended);
readXML(file, visitor);
PropsVisitor visitor(start_node, file.utf8Str(), default_mode, extended);
readXML(file.local8BitStr(), visitor);
if (visitor.hasException())
throw visitor.getException();
}
@@ -690,17 +690,17 @@ writeProperties (ostream &output, const SGPropertyNode * start_node,
void
writeProperties (const string &file, const SGPropertyNode * start_node,
writeProperties (const SGPath &path, const SGPropertyNode * start_node,
bool write_all, SGPropertyNode::Attribute archive_flag)
{
SGPath path(file.c_str());
path.create_dir(0755);
SGPath dpath(path);
dpath.create_dir(0755);
ofstream output(file.c_str());
ofstream output(path.local8BitStr().c_str());
if (output.good()) {
writeProperties(output, start_node, write_all, archive_flag);
} else {
throw sg_io_exception("Cannot open file", sg_location(file));
throw sg_io_exception("Cannot open file", sg_location(path.utf8Str()));
}
}

View File

@@ -29,7 +29,7 @@ void readProperties (std::istream &input, SGPropertyNode * start_node,
/**
* Read properties from an XML file.
*/
void readProperties (const std::string &file, SGPropertyNode * start_node,
void readProperties (const SGPath &file, SGPropertyNode * start_node,
int default_mode = 0, bool extended = false);
@@ -52,7 +52,7 @@ void writeProperties (std::ostream &output, const SGPropertyNode * start_node,
/**
* Write properties to an XML file.
*/
void writeProperties (const std::string &file,
void writeProperties (const SGPath &file,
const SGPropertyNode * start_node,
bool write_all = false,
SGPropertyNode::Attribute archive_flag = SGPropertyNode::ARCHIVE);

View File

@@ -14,6 +14,8 @@
#include "props.hxx"
#include "props_io.hxx"
#include <simgear/misc/sg_path.hxx>
using std::cout;
using std::cerr;
using std::endl;
@@ -394,7 +396,7 @@ int main (int ac, char ** av)
try {
cout << "Reading " << av[i] << endl;
SGPropertyNode root;
readProperties(av[i], &root);
readProperties(SGPath::fromLocal8Bit(av[i]), &root);
writeProperties(cout, &root, true);
cout << endl;
} catch (std::string &message) {

View File

@@ -33,6 +33,14 @@ sg_location::sg_location (const std::string& path, int line, int column)
setPath(path.c_str());
}
sg_location::sg_location (const SGPath& path, int line, int column)
: _line(line),
_column(column),
_byte(-1)
{
setPath(path.utf8Str().c_str());
}
sg_location::sg_location (const char* path, int line, int column)
: _line(line),
_column(column),
@@ -271,13 +279,6 @@ sg_io_exception::sg_io_exception( const std::string& message,
{
}
sg_io_exception::sg_io_exception( const std::string &message,
const SGPath& origin )
: sg_exception(message, origin.str())
{
}
sg_io_exception::~sg_io_exception () throw ()
{
}

View File

@@ -28,7 +28,8 @@ class sg_location
public:
enum {max_path = 1024};
sg_location ();
sg_location(const std::string& path, int line = -1, int column = -1);
sg_location(const std::string& path, int line = -1, int column = -1);
sg_location(const SGPath& path, int line = -1, int column = -1);
explicit sg_location(const char* path, int line = -1, int column = -1);
virtual ~sg_location() throw ();
virtual const char* getPath() const;
@@ -135,7 +136,6 @@ public:
sg_io_exception (const std::string &message, const std::string &origin = "");
sg_io_exception (const std::string &message, const sg_location &location,
const std::string &origin = "");
sg_io_exception (const std::string &message, const SGPath& origin);
virtual ~sg_io_exception () throw ();
virtual const std::string getFormattedMessage () const;