Initial copy from dali-adaptor repository
[platform/core/uifw/dali-adaptor-legacy.git] / dali / internal / adaptor-framework / android / file-stream-impl-android.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 #include <dali/integration-api/debug.h>
24
25 // INTERNAL INCLUDES
26 #include <dali/integration-api/adaptor-framework/android/android-framework.h>
27 #include <dali/internal/adaptor-framework/common/file-loader-impl.h>
28
29 namespace Dali
30 {
31
32 FileStream::Impl::Impl(const std::string& filename, uint8_t mode)
33 : mFileName( filename ),
34   mMode( mode ),
35   mBuffer( nullptr ),
36   mDataSize( 0 ),
37   mFile( nullptr )
38 {
39   DALI_ASSERT_DEBUG( !filename.empty() && "Can't open a empty filename." );
40   DALI_ASSERT_DEBUG( mode != 0 && "No mode is undefined behaviour" );
41 }
42
43 FileStream::Impl::Impl(uint8_t* buffer, size_t dataSize, uint8_t mode)
44 : mMode( mode ),
45   mBuffer( buffer ),
46   mDataSize( dataSize ),
47   mFile( nullptr )
48 {
49   DALI_ASSERT_DEBUG( buffer != 0 && "Can't open file on null buffer." );
50   DALI_ASSERT_DEBUG( dataSize > 0 && "Pointless to open file on empty buffer." );
51   DALI_ASSERT_DEBUG( mode != 0 && "No mode is undefined behaviour." );
52 }
53
54 FileStream::Impl::Impl(Dali::Vector<uint8_t>& buffer, size_t dataSize, uint8_t mode)
55 : mMode( mode ),
56   mBuffer( nullptr ),
57   mDataSize( dataSize ),
58   mFile( nullptr )
59 {
60   // Resize the buffer to ensure any null that gets written by
61   // fmemopen is written past the end of any data that is written to the buffer.
62   // (Workaround for a bug in Ubuntu that overwrites null to the last byte of the
63   // data block regardless of whether binary mode was specified. Tizen doesn't write
64   // null if binary mode is specified).
65
66   ++mDataSize;
67   buffer.Resize( mDataSize );
68   mBuffer = &buffer[0];
69
70   DALI_ASSERT_DEBUG( mBuffer != nullptr && "Can't open file on null buffer." );
71   DALI_ASSERT_DEBUG( dataSize > 0 && "Pointless to open file on empty buffer." );
72   DALI_ASSERT_DEBUG( mode != 0 && "No mode is undefined behaviour." );
73 }
74
75 FileStream::Impl::~Impl()
76 {
77   if( mFile )
78   {
79     const int closeFailed = fclose( mFile );
80     if( closeFailed )
81     {
82       DALI_LOG_WARNING( "File close failed for FILE: \"%p\".\n", static_cast<void*>( mFile ) );
83     }
84
85     mFile = nullptr;
86   }
87
88   if( mFileStream.is_open() )
89   {
90     mFileStream.close();
91   }
92 }
93
94 std::iostream& FileStream::Impl::GetStream()
95 {
96   if( mFile )
97   {
98     // return empty stream if FILE stream is open to avoid simultaneous access to the same file
99     return mFileStream;
100   }
101
102   if( mFileStream.is_open() )
103   {
104     return mFileStream;
105   }
106
107   if( mBufferStream.rdbuf()->in_avail() )
108   {
109     return mBufferStream;
110   }
111
112   int openMode = 0;
113
114   if( mMode & Dali::FileStream::APPEND )
115   {
116     openMode |= ( std::ios::out | std::ios::app );
117   }
118   else if( mMode & Dali::FileStream::WRITE )
119   {
120     openMode |= ( std::ios::out | std::ios::ate );
121   }
122
123   if( mMode & Dali::FileStream::READ )
124   {
125     openMode |= std::ios::in;
126   }
127
128   if( mMode & Dali::FileStream::BINARY )
129   {
130     openMode |= std::ios::binary;
131   }
132
133   if( !mFileName.empty() )
134   {
135     // TODO: it works only with text files, we need custom stream buffer implementation for binary and to avoid buffer copy
136     if( !( mMode & Dali::FileStream::WRITE ) && !( mMode & Dali::FileStream::APPEND ) && !( mMode & Dali::FileStream::BINARY ) )
137     {
138       std::streampos fileSize;
139       if( ReadFile( mFileName, fileSize, mFileBuffer, Dali::FileLoader::TEXT ) )
140       {
141         mBuffer = reinterpret_cast<uint8_t*>( &mFileBuffer[0] );
142         mDataSize = fileSize;
143         mBufferStream.str( std::string ( &mFileBuffer[0], fileSize ) );
144         if( !mBufferStream.rdbuf()->in_avail() )
145         {
146           DALI_LOG_ERROR( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%d\".\n",
147               static_cast<void*>( mBuffer ), static_cast<unsigned>( mDataSize ), static_cast<int>( openMode ) );
148         }
149         return mBufferStream;
150       }
151       else
152       {
153         DALI_LOG_ERROR( "stream open failed for: \"%s\", in mode: \"%d\".\n", mFileName.c_str(), static_cast<int>( openMode ) );
154       }
155     }
156     else
157     {
158       mFileStream.open( mFileName, static_cast<std::ios_base::openmode>( openMode ) );
159       if( !mFileStream.is_open() )
160       {
161         DALI_LOG_ERROR( "stream open failed for: \"%s\", in mode: \"%d\".\n", mFileName.c_str(), static_cast<int>( openMode ) );
162       }
163     }
164     return mFileStream;
165   }
166   else if( mBuffer )
167   {
168     mBufferStream.rdbuf()->pubsetbuf( reinterpret_cast<char*>( mBuffer ), mDataSize );
169     if( !mBufferStream.rdbuf()->in_avail() )
170     {
171       DALI_LOG_ERROR( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%d\".\n",
172           static_cast<void*>( mBuffer ), static_cast<unsigned>( mDataSize ), static_cast<int>( openMode ) );
173     }
174   }
175
176   return mBufferStream;
177 }
178
179 FILE* FileStream::Impl::GetFile()
180 {
181   if( mFileStream.is_open() || mBufferStream.rdbuf()->in_avail() )
182   {
183     // return empty FILE stream if the stream is open to avoid simultaneous access to the same file
184     return nullptr;
185   }
186
187   if( mFile )
188   {
189     return mFile;
190   }
191
192   char openMode[16] = { 0 };
193   int i = 0;
194
195   if( mMode & Dali::FileStream::APPEND )
196   {
197     openMode[i++] = 'a';
198   }
199   else if( mMode & Dali::FileStream::WRITE )
200   {
201     openMode[i++] = 'w';
202   }
203   else
204   {
205     openMode[i++] = 'r';
206   }
207
208   if( mMode & Dali::FileStream::BINARY )
209   {
210     openMode[i++] = 'b';
211   }
212
213   openMode[i++] = 0;
214
215   if( !mFileName.empty() )
216   {
217     if ( !( mMode & Dali::FileStream::WRITE ) && !( mMode & Dali::FileStream::APPEND ) )
218     {
219       std::streampos fileSize;
220       if ( ReadFile( mFileName, fileSize, mFileBuffer, ( mMode & Dali::FileStream::BINARY ) ? Dali::FileLoader::BINARY : Dali::FileLoader::TEXT ) )
221       {
222         mBuffer = reinterpret_cast<uint8_t*>( &mFileBuffer[0] );
223         mDataSize = fileSize;
224         mFile = fmemopen( mBuffer, mDataSize, openMode );
225         if( !mFile )
226         {
227           DALI_LOG_ERROR( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%s\".\n",
228               static_cast<void*>( mBuffer ), static_cast<unsigned>( mDataSize ), openMode );
229         }
230       }
231       else
232       {
233         DALI_LOG_ERROR( "read file failed for: \"%s\", in mode: \"%s\".\n", mFileName.c_str(), openMode );
234       }
235     }
236     else
237     {
238       mFile = fopen( mFileName.c_str(), openMode );
239       if( !mFile )
240       {
241         DALI_LOG_ERROR( "file open failed for: \"%s\", in mode: \"%s\".\n", mFileName.c_str(), openMode );
242       }
243     }
244   }
245   else if( mBuffer )
246   {
247     mFile = fmemopen( mBuffer, mDataSize, openMode );
248     if( !mFile )
249     {
250       DALI_LOG_ERROR( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%s\".\n",
251           static_cast<void*>( mBuffer ), static_cast<unsigned>( mDataSize ), openMode );
252     }
253   }
254
255   return mFile;
256 }
257
258 } // Dali