diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fe019a80..a9401e0c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -82,6 +82,8 @@ add_library(oatpp oatpp/core/data/stream/BufferInputStream.hpp oatpp/core/data/stream/ChunkedBuffer.cpp oatpp/core/data/stream/ChunkedBuffer.hpp + oatpp/core/data/stream/FileStream.cpp + oatpp/core/data/stream/FileStream.hpp oatpp/core/data/stream/Stream.cpp oatpp/core/data/stream/Stream.hpp oatpp/core/data/stream/StreamBufferedProxy.cpp diff --git a/src/oatpp/core/data/stream/FileStream.cpp b/src/oatpp/core/data/stream/FileStream.cpp new file mode 100644 index 00000000..7f167892 --- /dev/null +++ b/src/oatpp/core/data/stream/FileStream.cpp @@ -0,0 +1,142 @@ +/*************************************************************************** + * + * Project _____ __ ____ _ _ + * ( _ ) /__\ (_ _)_| |_ _| |_ + * )(_)( /(__)\ )( (_ _)(_ _) + * (_____)(__)(__)(__) |_| |_| + * + * + * Copyright 2018-present, Leonid Stryzhevskyi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ***************************************************************************/ + +#include "FileStream.hpp" + +namespace oatpp { namespace data{ namespace stream { + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FileInputStream + +FileInputStream::FileInputStream(std::FILE* file, bool ownsFile) + : m_file(file) + , m_ownsFile(ownsFile) + , m_ioMode(IOMode::NON_BLOCKING) +{} + +FileInputStream::FileInputStream(const char* filename) + : FileInputStream(std::fopen(filename, "rb"), true) +{ + if(!m_file) { + OATPP_LOGE("[oatpp::data::stream::FileInputStream::FileInputStream(filename)]", "Error. Can't open file '%s'.", filename); + throw std::runtime_error("[oatpp::data::stream::FileInputStream::FileInputStream(filename)]: Error. Can't open file."); + } +} + +FileInputStream::~FileInputStream() { + if(m_ownsFile) { + std::fclose(m_file); + } +} + +std::FILE* FileInputStream::getFile() { + return m_file; +} + +data::v_io_size FileInputStream::read(void *data, data::v_io_size count) { + return std::fread(data, 1, count, m_file); +} + +oatpp::async::Action FileInputStream::suggestInputStreamAction(data::v_io_size ioResult) { + + if(ioResult > 0) { + return oatpp::async::Action::createActionByType(oatpp::async::Action::TYPE_REPEAT); + } + + OATPP_LOGE("[oatpp::data::stream::FileInputStream::suggestInputStreamAction()]", "Error. ioResult=%d", ioResult); + + const char* message = + "Error. FileInputStream::suggestOutputStreamAction() method is called with (ioResult <= 0).\n" + "Conceptual error."; + + throw std::runtime_error(message); + +} + +void FileInputStream::setInputStreamIOMode(IOMode ioMode) { + m_ioMode = ioMode; +} + +IOMode FileInputStream::getInputStreamIOMode() { + return m_ioMode; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FileOutputStream + +FileOutputStream::FileOutputStream(std::FILE* file, bool ownsFile) + : m_file(file) + , m_ownsFile(ownsFile) + , m_ioMode(IOMode::NON_BLOCKING) +{} + +FileOutputStream::FileOutputStream(const char* filename, const char* mode) + : FileOutputStream(std::fopen(filename, mode), true) +{ + if(!m_file) { + OATPP_LOGE("[oatpp::data::stream::FileOutputStream::FileOutputStream(filename, mode)]", "Error. Can't open file '%s'.", filename); + throw std::runtime_error("[oatpp::data::stream::FileOutputStream::FileOutputStream(filename, mode)]: Error. Can't open file."); + } +} + +FileOutputStream::~FileOutputStream() { + if(m_ownsFile) { + std::fclose(m_file); + } +} + +std::FILE* FileOutputStream::getFile() { + return m_file; +} + +data::v_io_size FileOutputStream::write(const void *data, data::v_io_size count) { + return std::fwrite(data, 1, count, m_file); +} + + +oatpp::async::Action FileOutputStream::suggestOutputStreamAction(data::v_io_size ioResult) { + + if(ioResult > 0) { + return oatpp::async::Action::createActionByType(oatpp::async::Action::TYPE_REPEAT); + } + + OATPP_LOGE("[oatpp::data::stream::FileOutputStream::suggestInputStreamAction()]", "Error. ioResult=%d", ioResult); + + const char* message = + "Error. FileOutputStream::suggestOutputStreamAction() method is called with (ioResult <= 0).\n" + "Conceptual error."; + + throw std::runtime_error(message); + +} + +void FileOutputStream::setOutputStreamIOMode(IOMode ioMode) { + m_ioMode = ioMode; +} + +IOMode FileOutputStream::getOutputStreamIOMode() { + return m_ioMode; +} + +}}} diff --git a/src/oatpp/core/data/stream/FileStream.hpp b/src/oatpp/core/data/stream/FileStream.hpp new file mode 100644 index 00000000..fd8ea32a --- /dev/null +++ b/src/oatpp/core/data/stream/FileStream.hpp @@ -0,0 +1,169 @@ +/*************************************************************************** + * + * Project _____ __ ____ _ _ + * ( _ ) /__\ (_ _)_| |_ _| |_ + * )(_)( /(__)\ )( (_ _)(_ _) + * (_____)(__)(__)(__) |_| |_| + * + * + * Copyright 2018-present, Leonid Stryzhevskyi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ***************************************************************************/ + +#ifndef oatpp_data_stream_FileStream_hpp +#define oatpp_data_stream_FileStream_hpp + +#include "Stream.hpp" + +#include + +namespace oatpp { namespace data{ namespace stream { + +/** + * Wrapper over `std::FILE`. + */ +class FileInputStream : public InputStream { +private: + std::FILE* m_file; + bool m_ownsFile; + IOMode m_ioMode; +public: + + /** + * Constructor. + * @param file - file. + * @param ownsFile - if `true` then call close on `FileInputStream` destruction. + */ + FileInputStream(std::FILE* file, bool ownsFile); + + /** + * Constructor. + * @param filename - name of the file. + */ + FileInputStream(const char* filename); + + /** + * Virtual destructor. + */ + ~FileInputStream(); + + /** + * Get file. + * @return + */ + std::FILE* getFile(); + + /** + * Read data from stream up to count bytes, and return number of bytes actually read.
+ * It is a legal case if return result < count. Caller should handle this! + * @param data - buffer to read data to. + * @param count - size of the buffer. + * @return - actual number of bytes read. + */ + data::v_io_size read(void *data, data::v_io_size count) override; + + /** + * Implementation of InputStream must suggest async actions for I/O results.
+ * Suggested Action is used for scheduling coroutines in async::Executor.
+ * **Stream MUST always give the same file-handle if applicable** + * @param ioResult - result of the call to &l:InputStream::read ();. + * @return - &id:oatpp::async::Action;. + */ + oatpp::async::Action suggestInputStreamAction(data::v_io_size ioResult) override; + + /** + * Set stream I/O mode. + * @throws + */ + void setInputStreamIOMode(IOMode ioMode) override; + + /** + * Get stream I/O mode. + * @return + */ + IOMode getInputStreamIOMode() override; + +}; + +/** + * Wrapper over `std::FILE`. + */ +class FileOutputStream : public OutputStream { +private: + std::FILE* m_file; + bool m_ownsFile; + IOMode m_ioMode; +public: + + /** + * Constructor. + * @param file - file. + * @param ownsFile - if `true` then call close on `FileInputStream` destruction. + */ + FileOutputStream(std::FILE* file, bool ownsFile); + + /** + * Constructor. + * @param filename - name of the file. + * @param mode - ("wb" - create new/override, "ab" - create new/append). + */ + FileOutputStream(const char* filename, const char* mode = "wb"); + + /** + * Virtual destructor. + */ + ~FileOutputStream(); + + /** + * Get file. + * @return + */ + std::FILE* getFile(); + + /** + * Write data to stream up to count bytes, and return number of bytes actually written.
+ * It is a legal case if return result < count. Caller should handle this! + * @param data - data to write. + * @param count - number of bytes to write. + * @return - actual number of bytes written. &id:oatpp::data::v_io_size;. + */ + data::v_io_size write(const void *data, data::v_io_size count) override; + + /** + * Implementation of OutputStream must suggest async actions for I/O results.
+ * Suggested Action is used for scheduling coroutines in async::Executor.
+ * **Stream MUST always give the same file-handle if applicable** + * @param ioResult - result of the call to &l:OutputStream::write ();. + * @return - &id:oatpp::async::Action;. + */ + oatpp::async::Action suggestOutputStreamAction(data::v_io_size ioResult) override; + + /** + * Set stream I/O mode. + * @throws + */ + void setOutputStreamIOMode(IOMode ioMode) override; + + /** + * Get stream I/O mode. + * @return + */ + IOMode getOutputStreamIOMode() override; + +}; + +}}} + +#endif // oatpp_data_stream_FileStream_hpp