Add logs for file loading failure
[platform/core/uifw/dali-adaptor.git] / dali / internal / adaptor-framework / generic / file-stream-impl-generic.cpp
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 // CLASS HEADER
18 #include <dali/internal/adaptor-framework/common/file-stream-impl.h>
19
20 // EXTERNAL INCLUDES
21 #include <string>
22 #include <fstream>
23
24 #include <dali/integration-api/debug.h>
25
26 namespace Dali
27 {
28
29 FileStream::Impl::Impl(const std::string& filename, uint8_t mode)
30 : mFileName( filename ),
31   mMode( mode ),
32   mBuffer( nullptr ),
33   mDataSize( 0 ),
34   mFile( nullptr )
35 {
36   DALI_ASSERT_DEBUG( !filename.empty() && "Can't open a empty filename." );
37   DALI_ASSERT_DEBUG( mode != 0 && "No mode is undefined behaviour" );
38 }
39
40 FileStream::Impl::Impl(uint8_t* buffer, size_t dataSize, uint8_t mode)
41 : mMode( mode ),
42   mBuffer( buffer ),
43   mDataSize( dataSize ),
44   mFile( nullptr )
45 {
46   DALI_ASSERT_DEBUG( buffer != 0 && "Can't open file on null buffer." );
47   DALI_ASSERT_DEBUG( dataSize > 0 && "Pointless to open file on empty buffer." );
48   DALI_ASSERT_DEBUG( mode != 0 && "No mode is undefined behaviour." );
49 }
50
51 FileStream::Impl::Impl(Dali::Vector<uint8_t>& vector, size_t dataSize, uint8_t mode)
52 : mMode( mode ),
53   mBuffer( nullptr ),
54   mDataSize( dataSize ),
55   mFile( nullptr )
56 {
57   // Resize the buffer to ensure any null that gets written by
58   // fmemopen is written past the end of any data that is written to the buffer.
59   // (Workaround for a bug in Ubuntu that overwrites null to the last byte of the
60   // data block regardless of whether binary mode was specified. Tizen doesn't write
61   // null if binary mode is specified).
62
63   ++mDataSize;
64   vector.Resize( mDataSize );
65   mBuffer = &vector[0];
66
67   DALI_ASSERT_DEBUG( mBuffer != nullptr && "Can't open file on null buffer." );
68   DALI_ASSERT_DEBUG( dataSize > 0 && "Pointless to open file on empty buffer." );
69   DALI_ASSERT_DEBUG( mode != 0 && "No mode is undefined behaviour." );
70 }
71
72 FileStream::Impl::~Impl()
73 {
74   if( mFile )
75   {
76     const int closeFailed = fclose( mFile );
77     if( closeFailed )
78     {
79       DALI_LOG_WARNING( "File close failed for FILE: \"%p\".\n", static_cast<void*>( mFile ) );
80     }
81
82     mFile = nullptr;
83   }
84
85   if( mFileStream.is_open() )
86   {
87     mFileStream.close();
88   }
89 }
90
91 std::iostream& FileStream::Impl::GetStream()
92 {
93   if( mFile )
94   {
95     // return empty stream if FILE stream is open to avoid simultaneous access to the same file
96     return mFileStream;
97   }
98
99   if( mFileStream.is_open() )
100   {
101     return mFileStream;
102   }
103
104   if( mBufferStream.rdbuf()->in_avail() )
105   {
106     return mBufferStream;
107   }
108
109   int openMode = 0;
110
111   if( mMode & Dali::FileStream::APPEND )
112   {
113     openMode |= ( std::ios::out | std::ios::app );
114   }
115   else if( mMode & Dali::FileStream::WRITE )
116   {
117     openMode |= ( std::ios::out | std::ios::ate );
118   }
119
120   if( mMode & Dali::FileStream::READ )
121   {
122     openMode |= std::ios::in;
123   }
124
125   if( mMode & Dali::FileStream::BINARY )
126   {
127     openMode |= std::ios::binary;
128   }
129
130   if( !mFileName.empty() )
131   {
132     mFileStream.open( mFileName, static_cast<std::ios_base::openmode>( openMode ) );
133     if( !mFileStream.is_open() )
134     {
135       DALI_LOG_WARNING( "stream open failed for: \"%s\", in mode: \"%d\".\n", mFileName.c_str(), openMode );
136     }
137     return mFileStream;
138   }
139   else if( mBuffer )
140   {
141     mBufferStream.rdbuf()->pubsetbuf( reinterpret_cast<char*>( mBuffer ), mDataSize );
142     if( !mBufferStream.rdbuf()->in_avail() )
143     {
144       DALI_LOG_WARNING( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%d\".\n",
145           static_cast<void*>( mBuffer ), static_cast<unsigned>( mDataSize ), openMode );
146     }
147   }
148
149   return mBufferStream;
150 }
151
152 FILE* FileStream::Impl::GetFile()
153 {
154   if( mFileStream.is_open() || mBufferStream.rdbuf()->in_avail() )
155   {
156     // return empty FILE stream if the stream is open to avoid simultaneous access to the same file
157     return nullptr;
158   }
159
160   if( mFile )
161   {
162     return mFile;
163   }
164
165   char openMode[16] = { 0 };
166   int i = 0;
167
168   if( mMode & Dali::FileStream::APPEND )
169   {
170     openMode[i++] = 'a';
171   }
172   else if( mMode & Dali::FileStream::WRITE )
173   {
174     openMode[i++] = 'w';
175   }
176   else
177   {
178     openMode[i++] = 'r';
179   }
180
181   if( mMode & Dali::FileStream::BINARY )
182   {
183     openMode[i++] = 'b';
184   }
185
186   openMode[i++] = 0;
187
188   if( !mFileName.empty() )
189   {
190     mFile = fopen( mFileName.c_str(), openMode );
191     if( !mFile )
192     {
193       DALI_LOG_ERROR( "file open failed for: \"%s\", in mode: \"%s\".\n", mFileName.c_str(), openMode );
194     }
195   }
196   else if( mBuffer )
197   {
198     mFile = fmemopen( mBuffer, mDataSize, openMode );
199     if( !mFile )
200     {
201       DALI_LOG_ERROR( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%s\".\n",
202           static_cast<void*>( mBuffer ), static_cast<unsigned>( mDataSize ), openMode );
203     }
204   }
205
206   return mFile;
207 }
208
209 } // Dali