From b0dc938fc5fd49e890d25ca2b34d9ff3183d529b Mon Sep 17 00:00:00 2001 From: Anton Obzhirov Date: Tue, 9 Jul 2019 10:43:07 +0100 Subject: [PATCH] Add file stream API. Change-Id: I8558863e04052c075f90135b3558f0d5ee1d2a12 --- dali/devel-api/adaptor-framework/file-stream.cpp | 57 ++++++ dali/devel-api/adaptor-framework/file-stream.h | 121 +++++++++++++ dali/devel-api/file.list | 2 + .../adaptor-framework/common/file-stream-impl.h | 59 ++++++ dali/internal/adaptor-framework/file.list | 3 +- .../generic/file-stream-impl-generic.cpp | 199 +++++++++++++++++++++ dali/internal/system/common/file-reader.h | 12 +- dali/internal/system/common/file-writer.h | 6 +- 8 files changed, 449 insertions(+), 10 deletions(-) create mode 100644 dali/devel-api/adaptor-framework/file-stream.cpp create mode 100644 dali/devel-api/adaptor-framework/file-stream.h create mode 100644 dali/internal/adaptor-framework/common/file-stream-impl.h create mode 100644 dali/internal/adaptor-framework/generic/file-stream-impl-generic.cpp diff --git a/dali/devel-api/adaptor-framework/file-stream.cpp b/dali/devel-api/adaptor-framework/file-stream.cpp new file mode 100644 index 0000000..f6528e4 --- /dev/null +++ b/dali/devel-api/adaptor-framework/file-stream.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * + * 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. + */ + +// CLASS HEADER +#include + +// EXTERNAL INCLUDES + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +FileStream::FileStream(const std::string& filename, uint8_t mode) +{ + mImpl.reset( new Impl( filename, mode ) ); +} + +FileStream::FileStream(uint8_t* buffer, size_t dataSize, uint8_t mode) +{ + mImpl.reset( new Impl( buffer, dataSize, mode ) ); +} + +FileStream::FileStream(Dali::Vector& buffer, size_t dataSize, uint8_t mode) +{ + mImpl.reset( new Impl( buffer, dataSize, mode ) ); +} + +FileStream::~FileStream() = default; + +FileStream& FileStream::operator=(FileStream&&) = default; + +std::iostream& FileStream::GetStream() +{ + return mImpl->GetStream(); +} + +FILE* FileStream::GetFile() +{ + return mImpl->GetFile(); +} + +} // Dali diff --git a/dali/devel-api/adaptor-framework/file-stream.h b/dali/devel-api/adaptor-framework/file-stream.h new file mode 100644 index 0000000..8fa9999 --- /dev/null +++ b/dali/devel-api/adaptor-framework/file-stream.h @@ -0,0 +1,121 @@ +#ifndef DALI_FILE_STREAM_H +#define DALI_FILE_STREAM_H + +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * + * 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. + */ + +// EXTERNAL INCLUDES +#include +#include + +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +class DALI_ADAPTOR_API FileStream +{ +public: + + /** + * @brief File type formats + * The default format is binary + */ + enum FileMode ///< FileType format + { + BINARY = 0x1, ///< File stream will be opened as a binary + TEXT = 0x2, ///< File stream will be opened as text + READ = 0x4, ///< File stream will be opened for reading + WRITE = 0x8, ///< File stream will be opende for writing + }; + + /** + * Constructor + * @param[in] filename Filename of the file to open the stream for + * @param[in] mode How we want to open the stream. Binary or Text, Read or Write. Binary & Read default + */ + FileStream(const std::string& filename, uint8_t mode = BINARY | READ); + + /** + * Constructor + * @param[in] buffer Buffer to open the stream for. + * The buffer is not owned by FileStream and must be valid for entire lifetime of FileStream + * @param[in] dataSize The maximum size of the data in the buffer. + * @param[in] mode How we want to open the stream. Binary or Text, Read or Write. Binary & Read default + */ + FileStream(uint8_t* buffer, size_t dataSize, uint8_t mode = BINARY | READ); + + /** + * Constructor + * @param[in] buffer Buffer to open the stream for. + * The buffer is not owned by FileStream and must be valid for entire lifetime of FileStream + * @param[in] dataSize The maximum size of the data in the buffer. + * @param[in] mode How we want to open the stream. Binary or Text, Read or Write. Binary & Read default + */ + FileStream(Dali::Vector& buffer, size_t dataSize, uint8_t mode = BINARY | READ); + + /** + * Default move constructor + */ + FileStream(FileStream&&) = default; + + /** + * Non copyable + */ + FileStream(const FileStream&) = delete; + + /** + * Non assignable + */ + FileStream& operator=(const FileStream&) = delete; + + /** + * Move assignable + */ + FileStream& operator=(FileStream&&); + + /** + * Destructor + */ + ~FileStream(); + + /** + * @brief Returns the stream + * @return std::iostream. + */ + std::iostream& GetStream(); + + /** + * @brief Returns the file stream + * @return FILE. + */ + FILE* GetFile(); + +private: + + struct Impl; + std::unique_ptr mImpl; +}; + +} // Dali + +#endif // DALI_FILE_STREAM_H diff --git a/dali/devel-api/file.list b/dali/devel-api/file.list index e0495d7..19a2bbd 100755 --- a/dali/devel-api/file.list +++ b/dali/devel-api/file.list @@ -10,6 +10,7 @@ devel_api_src_files = \ $(adaptor_devel_api_dir)/adaptor-framework/event-thread-callback.cpp \ $(adaptor_devel_api_dir)/adaptor-framework/feedback-player.cpp \ $(adaptor_devel_api_dir)/adaptor-framework/file-loader.cpp \ + $(adaptor_devel_api_dir)/adaptor-framework/file-stream.cpp \ $(adaptor_devel_api_dir)/adaptor-framework/image-loading.cpp \ $(adaptor_devel_api_dir)/adaptor-framework/gif-loading.cpp \ $(adaptor_devel_api_dir)/adaptor-framework/input-method-context.cpp \ @@ -51,6 +52,7 @@ devel_api_adaptor_framework_header_files = \ $(adaptor_devel_api_dir)/adaptor-framework/feedback-plugin.h \ $(adaptor_devel_api_dir)/adaptor-framework/feedback-player.h \ $(adaptor_devel_api_dir)/adaptor-framework/file-loader.h \ + $(adaptor_devel_api_dir)/adaptor-framework/file-stream.h \ $(adaptor_devel_api_dir)/adaptor-framework/image-loader-input.h \ $(adaptor_devel_api_dir)/adaptor-framework/image-loader-plugin.h \ $(adaptor_devel_api_dir)/adaptor-framework/image-loading.h \ diff --git a/dali/internal/adaptor-framework/common/file-stream-impl.h b/dali/internal/adaptor-framework/common/file-stream-impl.h new file mode 100644 index 0000000..8b4e3ae --- /dev/null +++ b/dali/internal/adaptor-framework/common/file-stream-impl.h @@ -0,0 +1,59 @@ +#ifndef DALI_FILE_STREAM_IMPL_GENERIC_H +#define DALI_FILE_STREAM_IMPL_GENERIC_H + +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * + * 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. + */ + +// EXTERNAL INCLUDES +#include +#include +#include + +// INTERNAL INCLUDES + +namespace Dali +{ + +class FileStream::Impl +{ +public: + Impl(const std::string& filename, uint8_t mode); + + Impl(uint8_t* buffer, size_t dataSize, uint8_t mode); + + Impl(Dali::Vector& buffer, size_t dataSize, uint8_t mode); + + ~Impl(); + + std::iostream& GetStream(); + + FILE* GetFile(); + +private: + std::string mFileName; + uint8_t mMode; + uint8_t* mBuffer; // external buffer, not owned + size_t mDataSize; + + Dali::Vector mFileBuffer; // for internal usage only + FILE* mFile; + std::fstream mFileStream; + std::stringstream mBufferStream; +}; + +} // Dali + +#endif // DALI_FILE_STREAM_IMPL_GENERIC_H diff --git a/dali/internal/adaptor-framework/file.list b/dali/internal/adaptor-framework/file.list index 443056e..c818283 100644 --- a/dali/internal/adaptor-framework/file.list +++ b/dali/internal/adaptor-framework/file.list @@ -1,3 +1,4 @@ # module: adaptor-framework, backend: generic adaptor_framework_generic_src_files=\ - ${adaptor_framework_dir}/generic/file-loader-impl-generic.cpp + ${adaptor_framework_dir}/generic/file-loader-impl-generic.cpp \ + ${adaptor_framework_dir}/generic/file-stream-impl-generic.cpp diff --git a/dali/internal/adaptor-framework/generic/file-stream-impl-generic.cpp b/dali/internal/adaptor-framework/generic/file-stream-impl-generic.cpp new file mode 100644 index 0000000..7273b94 --- /dev/null +++ b/dali/internal/adaptor-framework/generic/file-stream-impl-generic.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * + * 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. + */ + +// CLASS HEADER +#include + +// EXTERNAL INCLUDES +#include +#include + +#include + +namespace Dali +{ + +FileStream::Impl::Impl(const std::string& filename, uint8_t mode) +: mFileName( filename ), + mMode( mode ), + mBuffer( nullptr ), + mDataSize( 0 ), + mFile( nullptr ) +{ + DALI_ASSERT_DEBUG( !filename.empty() && "Can't open a empty filename." ); + DALI_ASSERT_DEBUG( mode != 0 && "No mode is undefined behaviour" ); +} + +FileStream::Impl::Impl(uint8_t* buffer, size_t dataSize, uint8_t mode) +: mMode( mode ), + mBuffer( buffer ), + mDataSize( dataSize ), + mFile( nullptr ) +{ + DALI_ASSERT_DEBUG( buffer != 0 && "Can't open file on null buffer." ); + DALI_ASSERT_DEBUG( dataSize > 0 && "Pointless to open file on empty buffer." ); + DALI_ASSERT_DEBUG( mode != 0 && "No mode is undefined behaviour." ); +} + +FileStream::Impl::Impl(Dali::Vector& vector, size_t dataSize, uint8_t mode) +: mMode( mode ), + mBuffer( nullptr ), + mDataSize( dataSize ), + mFile( nullptr ) +{ + // Resize the buffer to ensure any null that gets written by + // fmemopen is written past the end of any data that is written to the buffer. + // (Workaround for a bug in Ubuntu that overwrites null to the last byte of the + // data block regardless of whether binary mode was specified. Tizen doesn't write + // null if binary mode is specified). + + ++mDataSize; + vector.Resize( mDataSize ); + mBuffer = &vector[0]; + + DALI_ASSERT_DEBUG( mBuffer != nullptr && "Can't open file on null buffer." ); + DALI_ASSERT_DEBUG( dataSize > 0 && "Pointless to open file on empty buffer." ); + DALI_ASSERT_DEBUG( mode != 0 && "No mode is undefined behaviour." ); +} + +FileStream::Impl::~Impl() +{ + if( mFile ) + { + const int closeFailed = fclose( mFile ); + if( closeFailed ) + { + DALI_LOG_WARNING( "File close failed for FILE: \"%p\".\n", static_cast( mFile ) ); + } + + mFile = nullptr; + } + + if( mFileStream.is_open() ) + { + mFileStream.close(); + } +} + +std::iostream& FileStream::Impl::GetStream() +{ + if( mFile ) + { + // return empty stream if FILE stream is open to avoid simultaneous access to the same file + return mFileStream; + } + + if( mFileStream.is_open() ) + { + return mFileStream; + } + + if( mBufferStream.rdbuf()->in_avail() ) + { + return mBufferStream; + } + + std::ios_base::openmode openMode = std::ios::ate; + if( mMode & Dali::FileStream::BINARY ) + { + openMode |= std::ios::binary; + } + + if( mMode & Dali::FileStream::WRITE ) + { + openMode |= std::ios::out; + } + else + { + openMode |= std::ios::in; + } + + if( !mFileName.empty() ) + { + mFileStream.open( mFileName, openMode ); + if( !mFileStream.is_open() ) + { + DALI_LOG_WARNING( "stream open failed for: \"%s\", in mode: \"%d\".\n", mFileName, static_cast( openMode ) ); + } + return mFileStream; + } + else if( mBuffer ) + { + mBufferStream.rdbuf()->pubsetbuf( reinterpret_cast( mBuffer ), mDataSize ); + if( !mBufferStream.rdbuf()->in_avail() ) + { + DALI_LOG_WARNING( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%d\".\n", + static_cast( mBuffer ), static_cast( mDataSize ), static_cast( openMode ) ); + } + } + + return mBufferStream; +} + +FILE* FileStream::Impl::GetFile() +{ + if( mFileStream.is_open() || mBufferStream.rdbuf()->in_avail() ) + { + // return empty FILE stream if the stream is open to avoid simultaneous access to the same file + return nullptr; + } + + if( mFile ) + { + return mFile; + } + + char openMode[16] = { 0 }; + int i = 0; + + if( mMode & Dali::FileStream::WRITE ) + { + openMode[i++] = 'w'; + } + else + { + openMode[i++] = 'r'; + } + + if( mMode & Dali::FileStream::BINARY ) + { + openMode[i++] = 'b'; + } + + openMode[i++] = 0; + + if( !mFileName.empty() ) + { + mFile = fopen( mFileName.c_str(), openMode ); + if( !mFile ) + { + DALI_LOG_WARNING( "file open failed for: \"%s\", in mode: \"%s\".\n", mFileName, openMode ); + } + } + else if( mBuffer ) + { + mFile = fmemopen( mBuffer, mDataSize, openMode ); + if( !mFile ) + { + DALI_LOG_WARNING( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%s\".\n", + static_cast( mBuffer ), static_cast( mDataSize ), openMode ); + } + } + + return mFile; +} + +} // Dali diff --git a/dali/internal/system/common/file-reader.h b/dali/internal/system/common/file-reader.h index 0893571..0b87fe3 100644 --- a/dali/internal/system/common/file-reader.h +++ b/dali/internal/system/common/file-reader.h @@ -18,7 +18,7 @@ */ // INTERNAL INCLUDES -#include +#include // EXTERNAL INCLUDES @@ -29,26 +29,26 @@ namespace Internal namespace Platform { -class FileReader : public FileCloser +class FileReader : public FileStream { public: FileReader( const std::string& filename ) - : FileCloser( filename.c_str(), "rb" ) + : FileStream( filename, FileStream::READ | FileStream::BINARY ) { } FileReader( Dali::Vector& vector ) - : FileCloser( &vector[0], vector.Size(), "rb" ) + : FileStream( &vector[0], vector.Size(), FileStream::READ | FileStream::BINARY ) { } FileReader( Dali::Vector& vector, size_t dataSize ) - : FileCloser( &vector[0], dataSize, "rb" ) + : FileStream( &vector[0], dataSize, FileStream::READ | FileStream::BINARY ) { } FileReader( uint8_t* data, size_t dataSize ) - : FileCloser( data, dataSize, "rb" ) + : FileStream( data, dataSize, FileStream::READ | FileStream::BINARY ) { } }; diff --git a/dali/internal/system/common/file-writer.h b/dali/internal/system/common/file-writer.h index da62c9c..6bc0c0c 100644 --- a/dali/internal/system/common/file-writer.h +++ b/dali/internal/system/common/file-writer.h @@ -18,7 +18,7 @@ */ // INTERNAL INCLUDES -#include +#include // EXTERNAL INCLUDES @@ -29,7 +29,7 @@ namespace Internal namespace Platform { -class FileWriter : public FileCloser +class FileWriter : public FileStream { public: /** @@ -39,7 +39,7 @@ public: * @param[in] dataSize the amount of data to be written */ FileWriter( Dali::Vector& vector, size_t dataSize ) - : FileCloser( vector, dataSize, "wb" ) + : FileStream( vector, dataSize, FileStream::WRITE | FileStream::BINARY ) { } }; -- 2.7.4