mirror of
https://github.com/pocoproject/poco.git
synced 2025-03-27 00:35:23 +01:00
feature(FileStream): Allow using Poco::FileStream to wrap arbitrary file handles/descriptors as C++ streams (#4424)
* Allow using Poco::FileStream to wrap arbitrary file handles/descriptors as C++ streams (#3444). * Allow opening a file descriptor/HANDLE as C++ stream. * FileStream: treat read from closed pipe as EOF. * chore(Filestream): conde style (naming) Co-Authored-By: Alex Fabijanic <alex@pocoproject.org> Co-Authored-By: Matej Kenda <matejken@gmail.com> * enh(FileStream): make FileIOS::open a virtual function. (#3444) * test(FileStream): unit test for FileStream::openHandle (#3444) * Update CONTRIBUTORS. * test(FileStream): Win32 unit test fix. * build(CMake): Require policy minimum version 3.15. --------- Co-authored-by: Daniel Grunwald <grunwald@axivion.com> Co-authored-by: Alex Fabijanic <alex@pocoproject.org>
This commit is contained in:
parent
1a0355f1b7
commit
065f9a0ff9
@ -1,4 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.5.0)
|
||||
cmake_policy(VERSION 3.15.0)
|
||||
|
||||
project(Poco)
|
||||
|
||||
|
@ -60,9 +60,11 @@ Friedrich Wilckens
|
||||
Pavle Dragišić
|
||||
Nino Belušić
|
||||
Kari Argillander
|
||||
Alexander B
|
||||
Alexander Bychuk
|
||||
Andrew Auclair
|
||||
Jochen Sprickerhof
|
||||
Jesse Hoogervorst
|
||||
Aron Budea
|
||||
zhuzeitou
|
||||
Daniel Grunwald
|
||||
|
||||
|
@ -56,6 +56,16 @@ public:
|
||||
~FileIOS();
|
||||
/// Destroys the stream.
|
||||
|
||||
virtual void open(const std::string& path, std::ios::openmode mode);
|
||||
/// Opens the file specified by path, using the given mode.
|
||||
///
|
||||
/// Throws a FileException (or a similar exception) if the file
|
||||
/// does not exist or is not accessible for other reasons and
|
||||
/// a new file cannot be created.
|
||||
|
||||
void openHandle(NativeHandle handle, std::ios::openmode mode);
|
||||
/// Takes ownership of the handle.
|
||||
|
||||
void close();
|
||||
/// Closes the file stream.
|
||||
///
|
||||
@ -108,7 +118,7 @@ public:
|
||||
~FileInputStream();
|
||||
/// Destroys the stream.
|
||||
|
||||
void open(const std::string& path, std::ios::openmode mode = std::ios::in);
|
||||
void open(const std::string& path, std::ios::openmode mode = std::ios::in) override;
|
||||
/// Opens the file specified by path, using the given mode, which
|
||||
/// will always include std::ios::in (even if not specified).
|
||||
///
|
||||
@ -151,7 +161,7 @@ public:
|
||||
~FileOutputStream();
|
||||
/// Destroys the FileOutputStream.
|
||||
|
||||
void open(const std::string& path, std::ios::openmode mode = std::ios::out | std::ios::trunc);
|
||||
void open(const std::string& path, std::ios::openmode mode = std::ios::out | std::ios::trunc) override;
|
||||
/// Opens the file specified by path, using the given mode, which
|
||||
/// always includes std::ios::out, even if not specified.
|
||||
///
|
||||
@ -196,7 +206,7 @@ public:
|
||||
~FileStream();
|
||||
/// Destroys the FileOutputStream.
|
||||
|
||||
void open(const std::string& path, std::ios::openmode mode = std::ios::out | std::ios::in);
|
||||
void open(const std::string& path, std::ios::openmode mode = std::ios::out | std::ios::in) override;
|
||||
/// Opens the file specified by path, using the given mode.
|
||||
///
|
||||
/// Throws a FileException (or a similar exception) if the file
|
||||
|
@ -42,6 +42,9 @@ public:
|
||||
void open(const std::string& path, std::ios::openmode mode);
|
||||
/// Opens the given file in the given mode.
|
||||
|
||||
void openHandle(NativeHandle fd, std::ios::openmode mode);
|
||||
/// Take ownership of the given file descriptor.
|
||||
|
||||
bool close();
|
||||
/// Closes the File stream buffer. Returns true if successful,
|
||||
/// false otherwise.
|
||||
|
@ -41,6 +41,9 @@ public:
|
||||
void open(const std::string& path, std::ios::openmode mode);
|
||||
/// Opens the given file in the given mode.
|
||||
|
||||
void openHandle(NativeHandle handle, std::ios::openmode mode);
|
||||
/// Take ownership of the given HANDLE.
|
||||
|
||||
bool close();
|
||||
/// Closes the File stream buffer. Returns true if successful,
|
||||
/// false otherwise.
|
||||
|
@ -35,6 +35,20 @@ FileIOS::~FileIOS()
|
||||
}
|
||||
|
||||
|
||||
void FileIOS::open(const std::string& path, std::ios::openmode mode)
|
||||
{
|
||||
clear();
|
||||
_buf.open(path, mode);
|
||||
}
|
||||
|
||||
|
||||
void FileIOS::openHandle(NativeHandle handle, std::ios::openmode mode)
|
||||
{
|
||||
clear();
|
||||
_buf.openHandle(handle, mode);
|
||||
}
|
||||
|
||||
|
||||
void FileIOS::close()
|
||||
{
|
||||
if (!_buf.close())
|
||||
@ -77,7 +91,7 @@ FileInputStream::FileInputStream():
|
||||
FileInputStream::FileInputStream(const std::string& path, std::ios::openmode mode):
|
||||
std::istream(&_buf)
|
||||
{
|
||||
open(path, mode | std::ios::in);
|
||||
open(path, mode);
|
||||
}
|
||||
|
||||
|
||||
@ -88,8 +102,7 @@ FileInputStream::~FileInputStream()
|
||||
|
||||
void FileInputStream::open(const std::string& path, std::ios::openmode mode)
|
||||
{
|
||||
clear();
|
||||
_buf.open(path, mode | std::ios::in);
|
||||
FileIOS::open(path, mode | std::ios::in);
|
||||
}
|
||||
|
||||
|
||||
@ -102,7 +115,7 @@ FileOutputStream::FileOutputStream():
|
||||
FileOutputStream::FileOutputStream(const std::string& path, std::ios::openmode mode):
|
||||
std::ostream(&_buf)
|
||||
{
|
||||
open(path, mode | std::ios::out);
|
||||
open(path, mode);
|
||||
}
|
||||
|
||||
|
||||
@ -113,8 +126,7 @@ FileOutputStream::~FileOutputStream()
|
||||
|
||||
void FileOutputStream::open(const std::string& path, std::ios::openmode mode)
|
||||
{
|
||||
clear();
|
||||
_buf.open(path, mode | std::ios::out);
|
||||
FileIOS::open(path, mode | std::ios::out);
|
||||
}
|
||||
|
||||
|
||||
@ -138,8 +150,7 @@ FileStream::~FileStream()
|
||||
|
||||
void FileStream::open(const std::string& path, std::ios::openmode mode)
|
||||
{
|
||||
clear();
|
||||
_buf.open(path, mode);
|
||||
FileIOS::open(path, mode);
|
||||
}
|
||||
|
||||
|
||||
|
@ -72,6 +72,22 @@ void FileStreamBuf::open(const std::string& path, std::ios::openmode mode)
|
||||
}
|
||||
|
||||
|
||||
void FileStreamBuf::openHandle(NativeHandle fd, std::ios::openmode mode)
|
||||
{
|
||||
poco_assert(_fd == -1);
|
||||
poco_assert(fd != -1);
|
||||
|
||||
_pos = 0;
|
||||
setMode(mode);
|
||||
resetBuffers();
|
||||
|
||||
_fd = fd;
|
||||
|
||||
if ((mode & std::ios::app) || (mode & std::ios::ate))
|
||||
seekoff(0, std::ios::end, mode);
|
||||
}
|
||||
|
||||
|
||||
int FileStreamBuf::readFromDevice(char* buffer, std::streamsize length)
|
||||
{
|
||||
if (_fd == -1) return -1;
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "Poco/FileStream.h"
|
||||
#include "Poco/File.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/UnicodeConverter.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@ -74,6 +73,22 @@ void FileStreamBuf::open(const std::string& path, std::ios::openmode mode)
|
||||
}
|
||||
|
||||
|
||||
void FileStreamBuf::openHandle(NativeHandle handle, std::ios::openmode mode)
|
||||
{
|
||||
poco_assert(_handle == INVALID_HANDLE_VALUE);
|
||||
poco_assert(handle != INVALID_HANDLE_VALUE);
|
||||
|
||||
_pos = 0;
|
||||
setMode(mode);
|
||||
resetBuffers();
|
||||
|
||||
_handle = handle;
|
||||
|
||||
if ((mode & std::ios::ate) || (mode & std::ios::app))
|
||||
seekoff(0, std::ios::end, mode);
|
||||
}
|
||||
|
||||
|
||||
int FileStreamBuf::readFromDevice(char* buffer, std::streamsize length)
|
||||
{
|
||||
if (INVALID_HANDLE_VALUE == _handle || !(getMode() & std::ios::in))
|
||||
@ -85,7 +100,14 @@ int FileStreamBuf::readFromDevice(char* buffer, std::streamsize length)
|
||||
DWORD bytesRead(0);
|
||||
BOOL rc = ReadFile(_handle, buffer, static_cast<DWORD>(length), &bytesRead, NULL);
|
||||
if (rc == 0)
|
||||
{
|
||||
if (GetLastError() == ERROR_BROKEN_PIPE)
|
||||
{
|
||||
// Read from closed pipe -> treat as EOF
|
||||
return 0;
|
||||
}
|
||||
File::handleLastError(_path);
|
||||
}
|
||||
|
||||
_pos += bytesRead;
|
||||
|
||||
|
@ -51,6 +51,54 @@ void FileStreamTest::testRead()
|
||||
}
|
||||
|
||||
|
||||
#if defined(POCO_OS_FAMILY_WINDOWS)
|
||||
#include "Poco/UnicodeConverter.h"
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
void FileStreamTest::testWriteReadNativeHandle()
|
||||
{
|
||||
Poco::FileOutputStream fos;
|
||||
Poco::FileInputStream fis;
|
||||
Poco::FileIOS::NativeHandle outHandle;
|
||||
|
||||
#if defined(POCO_OS_FAMILY_WINDOWS)
|
||||
char tmp[]={'\xc3', '\x84', '\xc3', '\x96', '\xc3', '\x9c', '\xc3', '\xa4', '\xc3', '\xb6', '\xc3', '\xbc', '\0'};
|
||||
std::string file(tmp);
|
||||
file.append(".txt");
|
||||
std::wstring utf16Path;
|
||||
Poco::UnicodeConverter::toUTF16(file, utf16Path);
|
||||
outHandle = CreateFileW(utf16Path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
assertTrue(outHandle != INVALID_HANDLE_VALUE);
|
||||
#else
|
||||
std::string file("testfile.txt");
|
||||
outHandle = ::open(file.c_str(), O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
#endif
|
||||
|
||||
Poco::TemporaryFile::registerForDeletion(file);
|
||||
|
||||
fos.openHandle(outHandle, std::ios::binary | std::ios::out | std::ios::trunc);
|
||||
fos << "sometestdata";
|
||||
fos.close();
|
||||
|
||||
Poco::FileIOS::NativeHandle inHandle;
|
||||
|
||||
#if defined(POCO_OS_FAMILY_WINDOWS)
|
||||
inHandle = CreateFileW(utf16Path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
assertTrue(inHandle != INVALID_HANDLE_VALUE);
|
||||
#else
|
||||
inHandle = ::open(file.c_str(), O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
#endif
|
||||
|
||||
fis.openHandle(inHandle, std::ios::in);
|
||||
assertTrue (fis.good());
|
||||
std::string read;
|
||||
fis >> read;
|
||||
assertTrue (!read.empty());
|
||||
}
|
||||
|
||||
|
||||
void FileStreamTest::testWrite()
|
||||
{
|
||||
#if defined(POCO_OS_FAMILY_WINDOWS)
|
||||
@ -304,6 +352,7 @@ CppUnit::Test* FileStreamTest::suite()
|
||||
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("FileStreamTest");
|
||||
|
||||
CppUnit_addTest(pSuite, FileStreamTest, testRead);
|
||||
CppUnit_addTest(pSuite, FileStreamTest, testWriteReadNativeHandle);
|
||||
CppUnit_addTest(pSuite, FileStreamTest, testWrite);
|
||||
CppUnit_addTest(pSuite, FileStreamTest, testReadWrite);
|
||||
CppUnit_addTest(pSuite, FileStreamTest, testOpen);
|
||||
|
@ -25,6 +25,7 @@ public:
|
||||
~FileStreamTest();
|
||||
|
||||
void testRead();
|
||||
void testWriteReadNativeHandle();
|
||||
void testWrite();
|
||||
void testReadWrite();
|
||||
void testOpen();
|
||||
|
Loading…
x
Reference in New Issue
Block a user