Add file stream API. 32/209732/3
authorAnton Obzhirov <a.obzhirov@samsung.com>
Tue, 9 Jul 2019 09:43:07 +0000 (10:43 +0100)
committerAnton Obzhirov <a.obzhirov@samsung.com>
Thu, 11 Jul 2019 09:20:01 +0000 (10:20 +0100)
Change-Id: I8558863e04052c075f90135b3558f0d5ee1d2a12

dali/devel-api/adaptor-framework/file-stream.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/file-stream.h [new file with mode: 0644]
dali/devel-api/file.list
dali/internal/adaptor-framework/common/file-stream-impl.h [new file with mode: 0644]
dali/internal/adaptor-framework/file.list
dali/internal/adaptor-framework/generic/file-stream-impl-generic.cpp [new file with mode: 0644]
dali/internal/system/common/file-reader.h
dali/internal/system/common/file-writer.h

diff --git a/dali/devel-api/adaptor-framework/file-stream.cpp b/dali/devel-api/adaptor-framework/file-stream.cpp
new file mode 100644 (file)
index 0000000..f6528e4
--- /dev/null
@@ -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 <dali/devel-api/adaptor-framework/file-stream.h>
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor-framework/common/file-stream-impl.h>
+
+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<uint8_t>& 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 (file)
index 0000000..8fa9999
--- /dev/null
@@ -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 <stdio.h>
+#include <stdint.h>
+
+#include <iostream>
+#include <string>
+#include <memory>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+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<uint8_t>& 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<Impl> mImpl;
+};
+
+} // Dali
+
+#endif // DALI_FILE_STREAM_H
index e0495d7..19a2bbd 100755 (executable)
@@ -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 (file)
index 0000000..8b4e3ae
--- /dev/null
@@ -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 <dali/devel-api/adaptor-framework/file-stream.h>
+#include <fstream>
+#include <sstream>
+
+// 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<uint8_t>& 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<char> mFileBuffer; // for internal usage only
+  FILE* mFile;
+  std::fstream mFileStream;
+  std::stringstream mBufferStream;
+};
+
+} // Dali
+
+#endif // DALI_FILE_STREAM_IMPL_GENERIC_H
index 443056e..c818283 100644 (file)
@@ -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 (file)
index 0000000..7273b94
--- /dev/null
@@ -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 <dali/internal/adaptor-framework/common/file-stream-impl.h>
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <fstream>
+
+#include <dali/integration-api/debug.h>
+
+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<uint8_t>& 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<void*>( 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<int>( openMode ) );
+    }
+    return mFileStream;
+  }
+  else if( mBuffer )
+  {
+    mBufferStream.rdbuf()->pubsetbuf( reinterpret_cast<char*>( 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<void*>( mBuffer ), static_cast<unsigned>( mDataSize ), static_cast<int>( 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<void*>( mBuffer ), static_cast<unsigned>( mDataSize ), openMode );
+    }
+  }
+
+  return mFile;
+}
+
+} // Dali
index 0893571..0b87fe3 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 // INTERNAL INCLUDES
-#include <dali/internal/system/common/file-closer.h>
+#include <dali/devel-api/adaptor-framework/file-stream.h>
 
 // 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<uint8_t>& vector )
-  : FileCloser( &vector[0], vector.Size(), "rb" )
+  : FileStream( &vector[0], vector.Size(), FileStream::READ | FileStream::BINARY )
   {
   }
 
   FileReader( Dali::Vector<uint8_t>& 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 )
   {
   }
 };
index da62c9c..6bc0c0c 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 // INTERNAL INCLUDES
-#include <dali/internal/system/common/file-closer.h>
+#include <dali/devel-api/adaptor-framework/file-stream.h>
 
 // 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<uint8_t>& vector, size_t dataSize )
-  : FileCloser( vector, dataSize, "wb" )
+  : FileStream( vector, dataSize, FileStream::WRITE | FileStream::BINARY )
   {
   }
 };