All file read operations should be done through FileLoader.
[platform/core/uifw/dali-adaptor.git] / dali / internal / system / common / file-closer.h
1 #ifndef DALI_INTERNAL_PLATFORM_FILECLOSER_H
2 #define DALI_INTERNAL_PLATFORM_FILECLOSER_H
3 /*
4  * Copyright (c) 2019 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 // INTERNAL INCLUDES
21 #include <dali/devel-api/adaptor-framework/file-loader.h>
22
23 // EXTERNAL INCLUDES
24 #include <cstdio>
25
26 namespace Dali
27 {
28 namespace Internal
29 {
30 namespace Platform
31 {
32
33 /**
34  * Opens files and closes them later even if an exception is thrown.
35  */
36 class FileCloser
37 {
38 protected: // prevent this class being directly instantiated
39
40   /**
41    * @brief Construct a FileCloser guarding a new FILE* for accessing the path passed in.
42    */
43   FileCloser( const char* const filename, const char* const mode )
44   {
45     DALI_ASSERT_DEBUG( filename != 0 && "Can't open a null filename." );
46     DALI_ASSERT_DEBUG( mode != 0 && "Null mode is undefined behaviour in spec." );
47
48     Dali::FileLoader::FileType fileType = Dali::FileLoader::FileType::TEXT;
49
50     const char* modeStr = mode;
51     while( *modeStr )
52     {
53       switch ( *modeStr )
54       {
55       case 'r':
56         break;
57       case 'b':
58         fileType = FileLoader::FileType::BINARY;
59         break;
60       // Still has to use fopen for append and write modes
61       case 'a':
62       case 'w':
63       case '+':
64         mFile = fopen( filename, mode );
65         return;
66       default:
67         break;
68       }
69
70       ++modeStr;
71     }
72
73     std::streampos bufferSize = 0;
74     if( !Dali::FileLoader::ReadFile( filename, bufferSize, mFileBuffer, fileType ) )
75     {
76       mFile = nullptr;
77     }
78     else
79     {
80       mFile = fmemopen( &mFileBuffer[0], bufferSize, mode );
81     }
82   }
83
84   /**
85    * @brief Construct a FileCloser guarding a FILE* for reading out of the memory buffer passed in.
86    */
87   FileCloser( uint8_t* buffer, size_t dataSize, const char* const mode )
88   : mFile( fmemopen( buffer, dataSize, mode) )
89   {
90   }
91
92   FileCloser( Dali::Vector<uint8_t>& vector, size_t dataSize, const char * const mode )
93   {
94     // Resize the buffer to ensure any null that gets written by
95     // fmemopen is written past the end of any data that is written to the buffer.
96     // (Workaround for a bug in Ubuntu that overwrites null to the last byte of the
97     // data block regardless of whether binary mode was specified. Tizen doesn't write
98     // null if binary mode is specified).
99     size_t bufferSize = dataSize;
100     ++bufferSize;
101     vector.Resize( bufferSize );
102
103     void * const buffer = &vector[0];
104     mFile = fmemopen( buffer, bufferSize, mode );
105
106     DALI_ASSERT_DEBUG( buffer != 0 && "Cant open file on null buffer." );
107     DALI_ASSERT_DEBUG( dataSize > 0 && "Pointless to open file on empty buffer." );
108     DALI_ASSERT_DEBUG( mode != 0 && "Null mode is undefined behaviour in spec." );
109
110     if( mFile == 0 )
111     {
112       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 );
113     }
114   }
115
116    /**
117     * @brief Destroy the FileCloser and clean up its FILE*.
118     */
119   ~FileCloser()
120   {
121     if( mFile != 0 )
122     {
123       const int closeFailed = fclose( mFile );
124
125       if ( closeFailed )
126       {
127         DALI_LOG_WARNING( "File close failed for FILE: \"%p\".\n", static_cast<void*>(mFile) );
128       }
129       mFile = 0;
130     }
131   }
132
133 public:
134   /**
135    * @return The FILE* guarded by this object.
136    */
137   FILE* GetFile()
138   {
139     return mFile;
140   }
141
142 private:
143
144   // Undefined
145   FileCloser( const FileCloser& fileCloser );
146
147   // Undefined
148   FileCloser& operator=( const FileCloser& fileCloser );
149
150 private:
151   FILE* mFile;
152   Dali::Vector<char> mFileBuffer;
153 };
154
155 } // namespace Platform
156
157 } // namespace Internal
158
159 } // namespace Dali
160
161 #endif // DALI_INTERNAL_PLATFORM_FILECLOSER_H