Added FileReader and FileWriter classes to wrap FileCloser 28/142128/1
authorDavid Steele <david.steele@samsung.com>
Wed, 2 Aug 2017 15:34:27 +0000 (16:34 +0100)
committerDavid Steele <david.steele@samsung.com>
Wed, 2 Aug 2017 20:14:06 +0000 (21:14 +0100)
Abstracted FileCloser to make the code tidier;

Changed FileWriter to extend the buffer so that on certain platforms,
the last data byte doesn't get overwritten.

Change-Id: I3ff2f252ce42462e33c483d65fb8fb69ff3549f8
Signed-off-by: David Steele <david.steele@samsung.com>
adaptors/devel-api/adaptor-framework/image-loading.cpp
platform-abstractions/portable/file-closer.h
platform-abstractions/portable/file-reader.h [new file with mode: 0644]
platform-abstractions/portable/file-writer.h [new file with mode: 0644]
platform-abstractions/tizen/image-loaders/image-loader.cpp
platform-abstractions/tizen/resource-loader/network/file-download.cpp
platform-abstractions/tizen/tizen-platform-abstraction.cpp

index e2f896b..2beb24d 100644 (file)
@@ -20,7 +20,7 @@
 // INTERNAL INCLUDES
 #include "image-loaders/image-loader.h"
 #include <resource-loader/network/file-download.h>
-#include <platform-abstractions/portable/file-closer.h>
+#include <platform-abstractions/portable/file-reader.h>
 #include "pixel-buffer-impl.h"
 
 namespace Dali
@@ -40,8 +40,8 @@ Devel::PixelBuffer LoadImageFromFile( const std::string& url, ImageDimensions si
 {
   Integration::BitmapResourceType resourceType( size, fittingMode, samplingMode, orientationCorrection );
 
-  Internal::Platform::FileCloser fc( url.c_str(), "rb");
-  FILE * const fp = fc.GetFile();
+  Internal::Platform::FileReader fileReader( url );
+  FILE * const fp = fileReader.GetFile();
   if( fp != NULL )
   {
     Integration::BitmapPtr bitmap;
@@ -93,17 +93,15 @@ Devel::PixelBuffer DownloadImageSynchronously( const std::string& url, ImageDime
                                                                     MAXIMUM_DOWNLOAD_IMAGE_SIZE );
   if( succeeded )
   {
-    void *blobBytes = static_cast<void*>(&dataBuffer[0]);
     size_t blobSize = dataBuffer.Size();
 
     DALI_ASSERT_DEBUG( blobSize > 0U );
-    DALI_ASSERT_DEBUG( blobBytes != 0U );
 
-    if( blobBytes != 0 && blobSize > 0U )
+    if( blobSize > 0U )
     {
       // Open a file handle on the memory buffer:
-      Dali::Internal::Platform::FileCloser fileCloser( blobBytes, blobSize, "rb" );
-      FILE * const fp = fileCloser.GetFile();
+      Dali::Internal::Platform::FileReader fileReader( dataBuffer, blobSize );
+      FILE * const fp = fileReader.GetFile();
       if ( NULL != fp )
       {
         Integration::BitmapPtr bitmap;
index bc4f362..78f6e5a 100644 (file)
@@ -34,13 +34,13 @@ namespace Platform
  */
 class FileCloser
 {
-public:
+protected: // prevent this class being directly instantiated
 
   /**
    * @brief Construct a FileCloser guarding a new FILE* for accessing the path passed in.
    */
-  FileCloser( const char * const filename, const char * const mode ) :
-    mFile(fopen(filename, mode))
+  FileCloser( const char * const filename, const char * const mode )
+  : mFile(fopen(filename, mode))
   {
     DALI_ASSERT_DEBUG( filename != 0 && "Cant open a null filename." );
     DALI_ASSERT_DEBUG( mode != 0 && "Null mode is undefined behaviour in spec." );
@@ -54,16 +54,32 @@ public:
   /**
    * @brief Construct a FileCloser guarding a FILE* for reading out of the memory buffer passed in.
    */
-  FileCloser( void * const buffer, const size_t bufferSize, const char * const mode ) :
-    mFile( fmemopen( buffer, bufferSize, mode ) )
+  FileCloser( uint8_t* buffer, size_t dataSize, const char * const mode )
+  : mFile( fmemopen( buffer, dataSize, mode) )
+  {
+  }
+
+  FileCloser( Dali::Vector<uint8_t>& vector, size_t dataSize, const char * const mode )
   {
+    // 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).
+    size_t bufferSize = dataSize;
+    ++bufferSize;
+    vector.Resize( bufferSize );
+
+    void * const buffer = &vector[0];
+    mFile = fmemopen( buffer, bufferSize, mode );
+
     DALI_ASSERT_DEBUG( buffer != 0 && "Cant open file on null buffer." );
-    DALI_ASSERT_DEBUG( bufferSize > 0 && "Pointless to open file on empty buffer." );
+    DALI_ASSERT_DEBUG( dataSize > 0 && "Pointless to open file on empty buffer." );
     DALI_ASSERT_DEBUG( mode != 0 && "Null mode is undefined behaviour in spec." );
 
     if( mFile == 0 )
     {
-      DALI_LOG_WARNING( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%s\".\n", static_cast<void*>(buffer), static_cast<unsigned>(bufferSize), mode );
+      DALI_LOG_WARNING( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%s\".\n", static_cast<void*>(buffer), static_cast<unsigned>(dataSize), mode );
     }
   }
 
@@ -84,6 +100,7 @@ public:
     }
   }
 
+public:
   /**
    * @return The FILE* guarded by this object.
    */
diff --git a/platform-abstractions/portable/file-reader.h b/platform-abstractions/portable/file-reader.h
new file mode 100644 (file)
index 0000000..8cfbbbe
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef DALI_INTERNAL_PORTABLE_FILE_READER_H
+#define DALI_INTERNAL_PORTABLE_FILE_READER_H
+
+/*
+ * Copyright (c) 2017 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.
+ */
+
+// INTERNAL INCLUDES
+#include "file-closer.h"
+
+// EXTERNAL INCLUDES
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Platform
+{
+
+class FileReader : public FileCloser
+{
+public:
+  FileReader( const std::string& filename )
+  : FileCloser( filename.c_str(), "rb" )
+  {
+  }
+
+  FileReader( Dali::Vector<uint8_t>& vector )
+  : FileCloser( &vector[0], vector.Size(), "rb" )
+  {
+  }
+
+  FileReader( Dali::Vector<uint8_t>& vector, size_t dataSize )
+  : FileCloser( &vector[0], dataSize, "rb" )
+  {
+  }
+
+  FileReader( uint8_t* data, size_t dataSize )
+  : FileCloser( data, dataSize, "rb" )
+  {
+  }
+};
+
+} /* namespace Platform */
+} /* namespace Internal */
+} /* namespace Dali */
+
+#endif // DALI_INTERNAL_PORTABLE_FILE_READER_H
diff --git a/platform-abstractions/portable/file-writer.h b/platform-abstractions/portable/file-writer.h
new file mode 100644 (file)
index 0000000..50617cb
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef DALI_INTERNAL_PORTABLE_FILE_WRITER_H
+#define DALI_INTERNAL_PORTABLE_FILE_WRITER_H
+
+/*
+ * Copyright (c) 2017 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.
+ */
+
+// INTERNAL INCLUDES
+#include "file-closer.h"
+
+// EXTERNAL INCLUDES
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Platform
+{
+
+class FileWriter : public FileCloser
+{
+public:
+  /**
+   * Opens a file pointer onto the memory for writing to.
+   * Note, in some implementations, the vector may be resized to be larger than dataSize.
+   * @param[in,out] vector The vector to write to
+   * @param[in] dataSize the amount of data to be written
+   */
+  FileWriter( Dali::Vector<uint8_t>& vector, size_t dataSize )
+  : FileCloser( vector, dataSize, "wb" )
+  {
+  }
+};
+
+} /* namespace Platform */
+} /* namespace Internal */
+} /* namespace Dali */
+
+#endif // DALI_INTERNAL_PORTABLE_FILE_WRITER_H
index ab76a83..16a012e 100644 (file)
@@ -30,7 +30,7 @@
 #include "loader-wbmp.h"
 #include "image-operations.h"
 #include "image-loader-input.h"
-#include "portable/file-closer.h"
+#include "portable/file-reader.h"
 
 using namespace Dali::Integration;
 
@@ -303,8 +303,8 @@ ResourcePointer LoadImageSynchronously( const Integration::BitmapResourceType& r
   ResourcePointer result;
   BitmapPtr bitmap = 0;
 
-  Internal::Platform::FileCloser fc( path.c_str(), "rb");
-  FILE * const fp = fc.GetFile();
+  Internal::Platform::FileReader fileReader( path );
+  FILE * const fp = fileReader.GetFile();
   if( fp != NULL )
   {
     bool success = ConvertStreamToBitmap( resource, path, fp, bitmap );
@@ -326,8 +326,8 @@ ImageDimensions  GetClosestImageSize( const std::string& filename,
   unsigned int width = 0;
   unsigned int height = 0;
 
-  Internal::Platform::FileCloser fc(filename.c_str(), "rb");
-  FILE *fp = fc.GetFile();
+  Internal::Platform::FileReader fileReader( filename );
+  FILE *fp = fileReader.GetFile();
   if (fp != NULL)
   {
     LoadBitmapFunction loaderFunction;
@@ -356,8 +356,6 @@ ImageDimensions  GetClosestImageSize( const std::string& filename,
   return ImageDimensions( width, height );
 }
 
-
-
 ImageDimensions GetClosestImageSize( Integration::ResourcePointer resourceBuffer,
                                      ImageDimensions size,
                                      FittingMode::Type fittingMode,
@@ -373,16 +371,11 @@ ImageDimensions GetClosestImageSize( Integration::ResourcePointer resourceBuffer
 
   if( encodedBlob != 0 )
   {
-    const size_t blobSize     = encodedBlob->GetVector().Size();
-    uint8_t * const blobBytes = &(encodedBlob->GetVector()[0]);
-    DALI_ASSERT_DEBUG( blobSize > 0U );
-    DALI_ASSERT_DEBUG( blobBytes != 0U );
-
-    if( blobBytes != 0 && blobSize > 0U )
+    if( encodedBlob->GetVector().Size() )
     {
       // Open a file handle on the memory buffer:
-      Internal::Platform::FileCloser fc( blobBytes, blobSize, "rb" );
-      FILE *fp = fc.GetFile();
+      Internal::Platform::FileReader fileReader( encodedBlob->GetVector() );
+      FILE *fp = fileReader.GetFile();
       if ( fp != NULL )
       {
         LoadBitmapFunction loaderFunction;
index ad50249..80f67fa 100755 (executable)
@@ -24,7 +24,7 @@
 #include <cstring>
 
 // INTERNAL INCLUDES
-#include "portable/file-closer.h"
+#include "portable/file-writer.h"
 
 #ifdef TPK_CURL_ENABLED
 #include <tpkp_curl.h>
@@ -100,11 +100,10 @@ size_t ChunkLoader(char *ptr, size_t size, size_t nmemb, void *userdata)
 CURLcode DownloadFileDataWithSize( CURL* curlHandle, Dali::Vector<uint8_t>& dataBuffer, size_t dataSize )
 {
   CURLcode result( CURLE_OK );
-  dataBuffer.Resize( dataSize );
 
   // create
-  Dali::Internal::Platform::FileCloser fileCloser( static_cast<void*>(&dataBuffer[0]), dataSize, "wb" );
-  FILE* dataBufferFilePointer = fileCloser.GetFile();
+  Dali::Internal::Platform::FileWriter fileWriter( dataBuffer, dataSize );
+  FILE* dataBufferFilePointer = fileWriter.GetFile();
   if( NULL != dataBufferFilePointer )
   {
     // we only want the body which contains the file data
@@ -189,6 +188,7 @@ bool DownloadFile( CURL* curlHandle,
   }
   else if( size > 0 )
   {
+    // If we know the size up front, allocate once and avoid chunk copies.
     dataSize = static_cast<size_t>( size );
     result = DownloadFileDataWithSize( curlHandle, dataBuffer, dataSize );
   }
index 959e338..1a8a876 100644 (file)
@@ -27,7 +27,7 @@
 
 // INTERNAL INCLUDES
 #include "image-loaders/image-loader.h"
-#include "portable/file-closer.h"
+#include "portable/file-reader.h"
 
 namespace Dali
 {
@@ -71,8 +71,8 @@ Integration::BitmapPtr TizenPlatformAbstraction::DecodeBuffer( const Integration
 {
   Integration::BitmapPtr bitmap = 0;
 
-  Dali::Internal::Platform::FileCloser fileCloser( buffer, size, "rb" );
-  FILE * const fp = fileCloser.GetFile();
+  Dali::Internal::Platform::FileReader fileReader( buffer, size );
+  FILE * const fp = fileReader.GetFile();
   if( fp )
   {
     bool result = ImageLoader::ConvertStreamToBitmap( resource, "", fp, bitmap );