Non-Qt implementations of file utils - needs testing.

This commit is contained in:
Matthias Koefferlein 2018-07-02 20:29:34 +02:00
parent 239b7ca3ff
commit 7fca6f5f31
7 changed files with 586 additions and 429 deletions

View File

@ -21,6 +21,7 @@
*/
#include "tlFileUtils.h"
#include "tlStream.h"
#include "tlLog.h"
#include "tlInternational.h"
@ -28,6 +29,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
namespace tl
{
@ -191,35 +193,140 @@ is_parent_path (const std::string &parent, const std::string &path)
return (is_same_file (parent, tl::combine_path (tl::join (parts, ""), "")));
}
bool rm_dir_recursive (const std::string &path)
std::vector<std::string> dir_entries (const std::string &s, bool with_files, bool with_dirs, bool without_dotfiles)
{
#if 0 // @@@
QDir dir (path);
std::vector<std::string> ee;
QStringList entries = dir.entryList (QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
for (QStringList::const_iterator e = entries.begin (); e != entries.end (); ++e) {
QFileInfo fi (dir.absoluteFilePath (*e));
if (fi.isDir ()) {
if (! rm_dir_recursive (fi.filePath ())) {
return false;
#if defined(_WIN32)
struct _wfinddata_t fileinfo;
intptr_t h = _wfindfirst (tl::to_wstring (s + "\\*.*").c_str (), &fileinfo);
if (h != -1) {
do {
std::string e = tl::to_string fileinfo.name);
if (e.empty () || e == "." || e == "..") {
continue;
}
} else if (fi.isFile ()) {
if (! dir.remove (*e)) {
tl::error << tr ("Unable to remove file: %1").arg (dir.absoluteFilePath (*e));
bool is_dir = ((fileinfo.attrib & _A_SUBDIR) != 0);
if ((e[0] != '.' || !without_dotfiles) && ((is_dir && with_dirs) || (!is_dir && with_files))) {
ee.push_back (e);
}
} while (_wfindnext (h, &fileinfo) == 0);
}
_wfindclose (h);
#else
DIR *h = opendir (tl::to_local (s).c_str ());
if (h) {
struct dirent *d;
while ((d = readdir (h)) != NULL) {
std::string e = tl::to_string_from_local (d->d_name);
if (e.empty () || e == "." || e == "..") {
continue;
}
bool is_dir = (d->d_type == DT_DIR);
if ((e[0] != '.' || !without_dotfiles) && ((is_dir && with_dirs) || (!is_dir && with_files))) {
ee.push_back (e);
}
}
closedir (h);
}
#endif
return ee;
}
bool mkdir (const std::string &path)
{
#if defined(_WIN32)
return _wunlink (tl::to_wstring (path).c_str ()) == 0;
#else
return unlink (tl::to_local (path).c_str ()) == 0;
#endif
}
bool mkpath (const std::string &p)
{
std::vector<std::string> parts = split_path (absolute_file_path (p));
size_t i = 0;
std::string front;
if (! parts.empty () && is_drive (parts.front ())) {
front = parts.front ();
++i;
}
while (i < parts.size ()) {
front += parts[i++];
if (! file_exists (front)) {
if (! mkdir (front)) {
tl::error << tr ("Unable to create directory: ") << front;
return false;
}
}
}
QString name = dir.dirName ();
if (dir.cdUp ()) {
if (! dir.rmdir (name)) {
tl::error << tr ("Unable to remove directory: %1").arg (dir.absoluteFilePath (name));
return true;
}
bool rm_file (const std::string &path)
{
#if defined(_WIN32)
return _wunlink (tl::to_wstring (path).c_str ()) == 0;
#else
return unlink (tl::to_local (path).c_str ()) == 0;
#endif
}
bool rm_dir (const std::string &path)
{
#if defined(_WIN32)
return _wrmdir (tl::to_wstring (path).c_str ()) == 0;
#else
return rmdir (tl::to_local (path).c_str ()) == 0;
#endif
}
bool rm_dir_recursive (const std::string &p)
{
std::vector<std::string> entries;
std::string path = tl::absolute_file_path (p);
entries = dir_entries (path, false /*without_files*/, true /*with_dirs*/);
for (std::vector<std::string>::const_iterator e = entries.begin (); e != entries.end (); ++e) {
if (! rm_dir_recursive (tl::combine_path (path, *e))) {
return false;
}
}
#endif
entries = dir_entries (path, true /*with_files*/, false /*without_dirs*/);
for (std::vector<std::string>::const_iterator e = entries.begin (); e != entries.end (); ++e) {
std::string tc = tl::combine_path (path, *e);
if (! rm_file (tc)) {
tl::error << tr ("Unable to remove file: ") << tc;
return false;
}
}
if (! rm_dir (path)) {
tl::error << tr ("Unable to remove directory: ") << path;
return false;
}
return true;
}
@ -227,72 +334,47 @@ bool rm_dir_recursive (const std::string &path)
bool
cp_dir_recursive (const std::string &source, const std::string &target)
{
#if 0 // @@@
QDir dir (source);
QDir dir_target (target);
std::vector<std::string> entries;
std::string path = tl::absolute_file_path (source);
std::string path_to = tl::absolute_file_path (target);
QStringList entries = dir.entryList (QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
for (QStringList::const_iterator e = entries.begin (); e != entries.end (); ++e) {
entries = dir_entries (path, false /*without_files*/, true /*with_dirs*/);
for (std::vector<std::string>::const_iterator e = entries.begin (); e != entries.end (); ++e) {
std::string tc = tl::combine_path (path_to, *e);
if (! mkpath (tc)) {
tl::error << tr ("Unable to create target directory: ") << tc;
return false;
}
if (! cp_dir_recursive (tl::combine_path (path, *e), tc)) {
return false;
}
}
QFileInfo fi (dir.absoluteFilePath (*e));
QFileInfo fi_target (dir_target.absoluteFilePath (*e));
if (fi.isDir ()) {
// Copy subdirectory
if (! fi_target.exists ()) {
if (! dir_target.mkdir (*e)) {
tl::error << tr ("Unable to create target directory: %1").arg (dir_target.absoluteFilePath (*e));
return false;
}
} else if (! fi_target.isDir ()) {
tl::error << tr ("Unable to create target directory (is a file already): %1").arg (dir_target.absoluteFilePath (*e));
return false;
}
if (! cp_dir_recursive (fi.filePath (), fi_target.filePath ())) {
return false;
}
entries = dir_entries (path, true /*with_files*/, false /*without_dirs*/);
for (std::vector<std::string>::const_iterator e = entries.begin (); e != entries.end (); ++e) {
// TODO: leave symlinks symlinks? How to copy symlinks with Qt?
} else if (fi.isFile ()) {
QFile file (fi.filePath ());
QFile file_target (fi_target.filePath ());
// copy the files
try {
if (! file.open (QIODevice::ReadOnly)) {
tl::error << tr ("Unable to open source file for reading: %1").arg (fi.filePath ());
return false;
}
if (! file_target.open (QIODevice::WriteOnly)) {
tl::error << tr ("Unable to open target file for writing: %1").arg (fi_target.filePath ());
return false;
}
size_t chunk_size = 64 * 1024;
while (! file.atEnd ()) {
QByteArray data = file.read (chunk_size);
file_target.write (data);
}
file.close ();
file_target.close ();
tl::OutputFile os_file (tl::combine_path (path_to, *e));
tl::OutputStream os (os_file);
tl::InputFile is_file (tl::combine_path (path, *e));
tl::InputStream is (is_file);
is.copy_to (os);
} catch (tl::Exception &ex) {
tl::error << tr ("Unable to copy file ") << tl::combine_path (path_to, *e) << tr (" to ") << tl::combine_path (path, *e)
<< tr ("(Error ") << ex.msg () << ")";
return false;
}
}
#endif
return true;
}
bool mkpath (const std::string &path)
{
// @@@
return false;
}
std::string absolute_path (const std::string &s)
{
std::vector<std::string> parts = split_path (absolute_file_path (s));
@ -305,39 +387,58 @@ std::string absolute_path (const std::string &s)
std::string current_dir ()
{
char *cwd;
#if defined(_WIN32)
cwd = _getcwd (NULL, 0);
#else
cwd = getcwd (NULL, 0);
#endif
wchar_t *cwd = _wgetcwd (NULL, 0);
if (cwd == NULL) {
return std::string ();
} else {
std::string cwds (cwd);
std::string cwds (tl::to_string (std::wstring (cwd)));
free (cwd);
return cwds;
}
#else
char *cwd = getcwd (NULL, 0);
if (cwd == NULL) {
return std::string ();
} else {
std::string cwds (tl::to_string_from_local (cwd));
free (cwd);
return cwds;
}
#endif
}
static std::pair<std::string, bool> absolute_path_of_existing (const std::string &s)
{
char *fp;
#if defined (_WIN32)
fp = _fullpath (NULL, s.c_str (), 0);
#else
fp = realpath (s.c_str (), NULL);
#endif
wchar_t *fp = _wfullpath (NULL, tl::to_wstring (s).c_str (), 0);
if (fp == NULL) {
return std::make_pair (std::string (), false);
} else {
std::string fps (fp);
std::string fps (tl::to_string (std::wstring (fp)));
free (fp);
return std::make_pair (fps, true);
}
#else
char *fp;
fp = realpath (tl::to_local (s).c_str (), NULL);
if (fp == NULL) {
return std::make_pair (std::string (), false);
} else {
std::string fps (tl::to_string_from_local (fp));
free (fp);
return std::make_pair (fps, true);
}
#endif
}
std::string absolute_file_path (const std::string &s)
@ -436,16 +537,25 @@ std::string extension (const std::string &s)
return tl::join (fnp, ".");
}
static int stat_func (const std::string &s, struct stat &st)
{
#if defined(_WIN32)
return _wstat (tl::to_wstring (s).c_str (), &st);
#else
return stat (tl::to_local (s).c_str (), &st);
#endif
}
bool file_exists (const std::string &p)
{
struct stat st;
return stat (p.c_str (), &st) == 0;
return stat_func (p, st) == 0;
}
bool is_dir (const std::string &p)
{
struct stat st;
if (stat (p.c_str (), &st) != 0) {
if (stat_func (p, st) != 0) {
return false;
} else {
return !S_ISREG (st.st_mode);
@ -466,8 +576,8 @@ bool is_same_file (const std::string &a, const std::string &b)
#if defined(_WIN32)
HANDLE h1 = ::CreateFile (a.c_str (), 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE h2 = ::CreateFile (b.c_str (), 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE h1 = ::CreateFileW (tl::to_wstring (a).c_str (), 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE h2 = ::CreateFileW (tl::to_wstring (b).c_str (), 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
bool result = false;
@ -493,10 +603,7 @@ bool is_same_file (const std::string &a, const std::string &b)
#else
struct stat sta, stb;
if (stat (a.c_str (), &sta) != 0) {
return false;
}
if (stat (b.c_str (), &stb) != 0) {
if (stat_func (a, sta) != 0 || stat_func (b, stb) != 0) {
return false;
}

View File

@ -96,6 +96,25 @@ bool TL_PUBLIC file_exists (const std::string &s);
*/
bool TL_PUBLIC is_dir (const std::string &s);
/**
* @brief Gets the directory entries for the given directory
* This method will NEVER return the ".." entry.
* @param with_files Includes all files
* @param with_dirs Include all directories
* @param without_dotfiles Exclude all ".*" files
*/
std::vector<std::string> TL_PUBLIC dir_entries (const std::string &s, bool with_files = true, bool with_dirs = true, bool without_dotfiles = false);
/**
* @brief Removes the given file and returns true on success
*/
bool TL_PUBLIC rm_file (const std::string &path);
/**
* @brief Removes the given directory and returns true on success
*/
bool TL_PUBLIC rm_dir (const std::string &path);
/**
* @brief Returns true, if the given path is the same directory of file than the other one
*/
@ -120,7 +139,7 @@ std::string TL_PUBLIC current_dir ();
* added if the path terminates with a separator (like "C:\" or "/home/user/").
* The idea is that the last element is the file name part.
*/
static std::vector<std::string> split_path (const std::string &p);
std::vector<std::string> split_path (const std::string &p);
}

View File

@ -124,185 +124,6 @@ public:
{ }
};
// ---------------------------------------------------------------------------------
// Input file delegate implementations - declaration and implementation
/**
* @brief A zlib input file delegate
*
* Implements the reader for a zlib stream
*/
class InputZLibFile
: public InputStreamBase
{
public:
/**
* @brief Open a file with the given path
*
* Opening a file is a prerequisite for reading from the
* object. open() will throw a FileOpenErrorException if
* an error occurs.
*
* @param path The (relative) path of the file to open
*/
InputZLibFile (const std::string &path);
/**
* @brief Close the file
*
* The destructor will automatically close the file.
*/
virtual ~InputZLibFile ();
/**
* @brief Read from a file
*
* Implements the basic read method.
* Will throw a ZLibReadErrorException if an error occurs.
*/
virtual size_t read (char *b, size_t n);
virtual void reset ();
virtual void close ();
virtual std::string source () const
{
return m_source;
}
virtual std::string absolute_path () const;
virtual std::string filename () const;
private:
std::string m_source;
gzFile m_zs;
};
/**
* @brief A simple input file delegate
*
* Implements the reader for ordinary files.
*/
class InputFile
: public InputStreamBase
{
public:
/**
* @brief Open a file with the given path
*
* Opening a file is a prerequisite for reading from the
* object. open() will throw a FileOpenErrorException if
* an error occurs.
*
* @param path The (relative) path of the file to open
* @param read True, if the file should be read, false on write.
*/
InputFile (const std::string &path);
/**
* @brief Close the file
*
* The destructor will automatically close the file.
*/
virtual ~InputFile ();
virtual size_t read (char *b, size_t n);
virtual void reset ();
virtual void close ();
virtual std::string source () const
{
return m_source;
}
virtual std::string absolute_path () const;
virtual std::string filename () const;
private:
std::string m_source;
int m_fd;
};
/**
* @brief A simple pipe input delegate
*
* Implements the reader for pipe streams
*/
class InputPipe
: public InputStreamBase
{
public:
/**
* @brief Open a stream by connecting with the stdout of a given command
*
* Opening a pipe is a prerequisite for reading from the
* object. open() will throw a FilePOpenErrorException if
* an error occurs - commonly if the command cannot be executed.
* This implementation is based on popen ().
*
* @param cmd The command to execute
* @param read True, if the file should be read, false on write.
*/
InputPipe (const std::string &path);
/**
* @brief Close the pipe
*
* The destructor will automatically close the pipe.
*/
virtual ~InputPipe ();
/**
* @brief Read from the pipe
*
* Implements the basic read method.
* Will throw a FilePReadErrorException if an error occurs.
*/
virtual size_t read (char *b, size_t n);
/**
* @brief Reset to the beginning of the file
*/
virtual void reset ();
/**
* @brief Closes the pipe
*/
virtual void close ();
/**
* @brief Get the source specification (the file name)
*
* Returns an empty string if no file name is available.
*/
virtual std::string source () const
{
// No source (in the sense of a file name) is available ..
return std::string ();
}
virtual std::string absolute_path () const
{
// No source (in the sense of a file name) is available ..
return std::string ();
}
virtual std::string filename () const
{
// No source (in the sense of a file name) is available ..
return std::string ();
}
private:
FILE *m_file;
std::string m_source;
};
// ---------------------------------------------------------------
// InputStream implementation
@ -490,8 +311,7 @@ InputStream::read_all ()
return str;
}
void
InputStream::copy_to (tl::OutputStream &os)
void InputStream::copy_to(tl::OutputStream &os)
{
const size_t chunk = 65536;
char b [chunk];
@ -794,147 +614,6 @@ InputZLibFile::filename () const
return tl::filename (m_source);
}
// ---------------------------------------------------------------------------------
// OutputStreamBase implementations - declarations and implementation
/**
* @brief A zlib output file delegate
*
* Implements the writer for a zlib stream
*/
class OutputZLibFile
: public OutputStreamBase
{
public:
/**
* @brief Open a file with the given path
*
* Opening a file is a prerequisite for reading from the
* object. open() will throw a FileOpenErrorException if
* an error occurs.
*
* @param path The (relative) path of the file to open
*/
OutputZLibFile (const std::string &path);
/**
* @brief Close the file
*
* The destructor will automatically close the file.
*/
virtual ~OutputZLibFile ();
/**
* @brief Write to a file
*
* Implements the basic write method.
* Will throw a ZLibWriteErrorException if an error occurs.
*/
virtual void write (const char *b, size_t n);
private:
std::string m_source;
gzFile m_zs;
};
/**
* @brief A simple output file delegate
*
* Implements the writer for ordinary files.
*/
class OutputFile
: public OutputStreamBase
{
public:
/**
* @brief Open a file with the given path
*
* Opening a file is a prerequisite for reading from the
* object. open() will throw a FileOpenErrorException if
* an error occurs.
*
* @param path The (relative) path of the file to open
* @param read True, if the file should be read, false on write.
*/
OutputFile (const std::string &path);
/**
* @brief Close the file
*
* The destructor will automatically close the file.
*/
virtual ~OutputFile ();
/**
* @brief Seek to the specified position
*
* Writing continues at that position after a seek.
*/
virtual void seek (size_t s);
/**
* @brief Returns a value indicating whether that stream supports seek
*/
bool supports_seek ()
{
return true;
}
/**
* @brief Write to a file
*
* Implements the basic write method.
* Will throw a FileWriteErrorException if an error occurs.
*/
virtual void write (const char *b, size_t n);
private:
std::string m_source;
int m_fd;
};
/**
* @brief A simple pipe output delegate
*
* Implements the writer for pipe streams
*/
class OutputPipe
: public OutputStreamBase
{
public:
/**
* @brief Open a stream by connecting with the stdout of a given command
*
* Opening a pipe is a prerequisite for reading from the
* object. open() will throw a FilePOpenErrorException if
* an error occurs - commonly if the command cannot be executed.
* This implementation is based on popen ().
*
* @param cmd The command to execute
* @param read True, if the file should be read, false on write.
*/
OutputPipe (const std::string &path);
/**
* @brief Close the pipe
*
* The destructor will automatically close the pipe.
*/
virtual ~OutputPipe ();
/**
* @brief Write to a file
*
* Implements the basic write method.
* Will throw a FilePWriteErrorException if an error occurs.
*/
virtual void write (const char *b, size_t n);
private:
FILE *m_file;
std::string m_source;
};
// ---------------------------------------------------------------
// OutputStream implementation

View File

@ -166,6 +166,182 @@ private:
size_t m_length, m_pos;
};
/**
* @brief A zlib input file delegate
*
* Implements the reader for a zlib stream
*/
class InputZLibFile
: public InputStreamBase
{
public:
/**
* @brief Open a file with the given path
*
* Opening a file is a prerequisite for reading from the
* object. open() will throw a FileOpenErrorException if
* an error occurs.
*
* @param path The (relative) path of the file to open
*/
InputZLibFile (const std::string &path);
/**
* @brief Close the file
*
* The destructor will automatically close the file.
*/
virtual ~InputZLibFile ();
/**
* @brief Read from a file
*
* Implements the basic read method.
* Will throw a ZLibReadErrorException if an error occurs.
*/
virtual size_t read (char *b, size_t n);
virtual void reset ();
virtual void close ();
virtual std::string source () const
{
return m_source;
}
virtual std::string absolute_path () const;
virtual std::string filename () const;
private:
std::string m_source;
gzFile m_zs;
};
/**
* @brief A simple input file delegate
*
* Implements the reader for ordinary files.
*/
class InputFile
: public InputStreamBase
{
public:
/**
* @brief Open a file with the given path
*
* Opening a file is a prerequisite for reading from the
* object. open() will throw a FileOpenErrorException if
* an error occurs.
*
* @param path The (relative) path of the file to open
* @param read True, if the file should be read, false on write.
*/
InputFile (const std::string &path);
/**
* @brief Close the file
*
* The destructor will automatically close the file.
*/
virtual ~InputFile ();
virtual size_t read (char *b, size_t n);
virtual void reset ();
virtual void close ();
virtual std::string source () const
{
return m_source;
}
virtual std::string absolute_path () const;
virtual std::string filename () const;
private:
std::string m_source;
int m_fd;
};
/**
* @brief A simple pipe input delegate
*
* Implements the reader for pipe streams
*/
class InputPipe
: public InputStreamBase
{
public:
/**
* @brief Open a stream by connecting with the stdout of a given command
*
* Opening a pipe is a prerequisite for reading from the
* object. open() will throw a FilePOpenErrorException if
* an error occurs - commonly if the command cannot be executed.
* This implementation is based on popen ().
*
* @param cmd The command to execute
* @param read True, if the file should be read, false on write.
*/
InputPipe (const std::string &path);
/**
* @brief Close the pipe
*
* The destructor will automatically close the pipe.
*/
virtual ~InputPipe ();
/**
* @brief Read from the pipe
*
* Implements the basic read method.
* Will throw a FilePReadErrorException if an error occurs.
*/
virtual size_t read (char *b, size_t n);
/**
* @brief Reset to the beginning of the file
*/
virtual void reset ();
/**
* @brief Closes the pipe
*/
virtual void close ();
/**
* @brief Get the source specification (the file name)
*
* Returns an empty string if no file name is available.
*/
virtual std::string source () const
{
// No source (in the sense of a file name) is available ..
return std::string ();
}
virtual std::string absolute_path () const
{
// No source (in the sense of a file name) is available ..
return std::string ();
}
virtual std::string filename () const
{
// No source (in the sense of a file name) is available ..
return std::string ();
}
private:
FILE *m_file;
std::string m_source;
};
// ---------------------------------------------------------------------------------
/**
@ -248,8 +424,9 @@ public:
/**
* @brief Copies the content of the stream to the output stream
* Throws an exception on error.
*/
void copy_to (tl::OutputStream &os);
void copy_to(tl::OutputStream &os);
/**
* @brief Enable uncompression of the following DEFLATE-compressed block
@ -604,6 +781,144 @@ private:
std::ostringstream m_stream;
};
/**
* @brief A zlib output file delegate
*
* Implements the writer for a zlib stream
*/
class OutputZLibFile
: public OutputStreamBase
{
public:
/**
* @brief Open a file with the given path
*
* Opening a file is a prerequisite for reading from the
* object. open() will throw a FileOpenErrorException if
* an error occurs.
*
* @param path The (relative) path of the file to open
*/
OutputZLibFile (const std::string &path);
/**
* @brief Close the file
*
* The destructor will automatically close the file.
*/
virtual ~OutputZLibFile ();
/**
* @brief Write to a file
*
* Implements the basic write method.
* Will throw a ZLibWriteErrorException if an error occurs.
*/
virtual void write (const char *b, size_t n);
private:
std::string m_source;
gzFile m_zs;
};
/**
* @brief A simple output file delegate
*
* Implements the writer for ordinary files.
*/
class OutputFile
: public OutputStreamBase
{
public:
/**
* @brief Open a file with the given path
*
* Opening a file is a prerequisite for reading from the
* object. open() will throw a FileOpenErrorException if
* an error occurs.
*
* @param path The (relative) path of the file to open
* @param read True, if the file should be read, false on write.
*/
OutputFile (const std::string &path);
/**
* @brief Close the file
*
* The destructor will automatically close the file.
*/
virtual ~OutputFile ();
/**
* @brief Seek to the specified position
*
* Writing continues at that position after a seek.
*/
virtual void seek (size_t s);
/**
* @brief Returns a value indicating whether that stream supports seek
*/
bool supports_seek ()
{
return true;
}
/**
* @brief Write to a file
*
* Implements the basic write method.
* Will throw a FileWriteErrorException if an error occurs.
*/
virtual void write (const char *b, size_t n);
private:
std::string m_source;
int m_fd;
};
/**
* @brief A simple pipe output delegate
*
* Implements the writer for pipe streams
*/
class OutputPipe
: public OutputStreamBase
{
public:
/**
* @brief Open a stream by connecting with the stdout of a given command
*
* Opening a pipe is a prerequisite for reading from the
* object. open() will throw a FilePOpenErrorException if
* an error occurs - commonly if the command cannot be executed.
* This implementation is based on popen ().
*
* @param cmd The command to execute
* @param read True, if the file should be read, false on write.
*/
OutputPipe (const std::string &path);
/**
* @brief Close the pipe
*
* The destructor will automatically close the pipe.
*/
virtual ~OutputPipe ();
/**
* @brief Write to a file
*
* Implements the basic write method.
* Will throw a FilePWriteErrorException if an error occurs.
*/
virtual void write (const char *b, size_t n);
private:
FILE *m_file;
std::string m_source;
};
// ---------------------------------------------------------------------------------
/**

View File

@ -40,9 +40,9 @@ static std::locale c_locale ("C");
// -------------------------------------------------------------------------
// Conversion of UTF8 to wchar_t
static std::vector<wchar_t> utf8_to_wchar (const std::string &s)
std::wstring to_wstring (const std::string &s)
{
std::vector<wchar_t> ws;
std::wstring ws;
const char *cpe = s.c_str () + s.size ();
for (const char *cp = s.c_str (); cp < cpe; ) {
@ -61,10 +61,10 @@ static std::vector<wchar_t> utf8_to_wchar (const std::string &s)
if (c32 >= 0x10000) {
c32 -= 0x10000;
ws.push_back (wchar_t (0xd800 + (c32 >> 10)));
ws.push_back (wchar_t (0xdc00 + (c32 & 0x3ff)));
ws += wchar_t (0xd800 + (c32 >> 10));
ws += wchar_t (0xdc00 + (c32 & 0x3ff));
} else {
ws.push_back (wchar_t (c32));
ws += wchar_t (c32);
}
}
@ -72,11 +72,11 @@ static std::vector<wchar_t> utf8_to_wchar (const std::string &s)
return ws;
}
static std::string wchar_to_utf8 (const std::vector<wchar_t> &ws)
std::string to_string (const std::wstring &ws)
{
std::string s;
for (std::vector<wchar_t>::const_iterator c = ws.begin (); c != ws.end (); ++c) {
for (std::wstring::const_iterator c = ws.begin (); c != ws.end (); ++c) {
uint32_t c32 = *c;
if (c32 >= 0xd800 && c + 1 < ws.end ()) {
@ -140,20 +140,36 @@ std::string tl::db_to_string (double d)
std::string tl::to_upper_case (const std::string &s)
{
std::vector<wchar_t> ws = utf8_to_wchar (s);
for (std::vector<wchar_t>::iterator c = ws.begin (); c != ws.end (); ++c) {
std::wstring ws = to_wstring (s);
for (std::wstring::iterator c = ws.begin (); c != ws.end (); ++c) {
*c = towupper (*c);
}
return wchar_to_utf8 (ws);
return to_string (ws);
}
std::string tl::to_lower_case (const std::string &s)
{
std::vector<wchar_t> ws = utf8_to_wchar (s);
for (std::vector<wchar_t>::iterator c = ws.begin (); c != ws.end (); ++c) {
std::wstring ws = to_wstring (s);
for (std::wstring::iterator c = ws.begin (); c != ws.end (); ++c) {
*c = towlower (*c);
}
return wchar_to_utf8 (ws);
return to_string (ws);
}
std::string to_local (const std::string &s)
{
std::auto_ptr<char> buffer (new char [MB_CUR_MAX]); // MB_CUR_MAX isn't a constant
std::string ls;
std::wstring ws = to_wstring (s);
for (std::wstring::const_iterator c = ws.begin (); c != ws.end (); ++c) {
int length = wctomb (buffer.get (), *c);
for (int i = 0; i < length; ++i) {
ls += buffer.get ()[i];
}
}
return ls;
}
std::string to_string_from_local (const char *cp)
@ -161,7 +177,7 @@ std::string to_string_from_local (const char *cp)
mbstate_t state;
memset ((void *) &state, 0, sizeof (mbstate_t));
std::vector<wchar_t> ws;
std::wstring ws;
size_t max = strlen (cp);
@ -172,12 +188,12 @@ std::string to_string_from_local (const char *cp)
if (length < 1) {
break;
}
ws.push_back (wc);
ws += wc;
cp += length;
max -= length;
}
return wchar_to_utf8 (ws);
return to_string (ws);
}
// -------------------------------------------------------------------------

View File

@ -34,7 +34,9 @@
#include "tlException.h"
#include "tlVariant.h"
#if defined(HAVE_QT)
class QImage;
#endif
namespace tl {
@ -262,6 +264,7 @@ TL_PUBLIC std::string to_string (float d, int prec);
TL_PUBLIC std::string to_string (const unsigned char *cp, int length);
TL_PUBLIC std::string to_string (const char *cp, int length);
TL_PUBLIC std::string to_string_from_local (const char *cp);
TL_PUBLIC std::string to_local (const std::string &s);
template <class T> inline std::string to_string (const T &o) { return o.to_string (); }
template <> inline std::string to_string (const double &d) { return to_string (d, 12); }
@ -287,8 +290,20 @@ template <> inline std::string to_string (const std::string &s) { return s; }
// to a variant object
template <> inline std::string to_string (const tl::Variant &v) { return v.to_parsable_string (); }
#if defined(HAVE_QT)
// some dummy conversions provided for tl::Variant implementation
template <> inline std::string to_string (const QImage &) { return std::string (); }
#endif
/**
* @brief Converts UTF-8 to wide character string
*/
std::wstring TL_PUBLIC to_wstring (const std::string &s);
/**
* @brief Converts a wide character string to UTF-8
*/
std::string TL_PUBLIC to_string (const std::wstring &ws);
/**
* @brief Convert to a quoted string

View File

@ -24,6 +24,10 @@
#include "tlFileUtils.h"
#include "tlUnitTest.h"
#if defined(HAVE_QT)
// A few things we cross-check against Qt
#include <QDir>
#include <QFileInfo>
#include <QFile>
@ -161,3 +165,5 @@ TEST (3)
file.close ();
}
}
#endif