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