2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <dali/internal/adaptor-framework/common/file-stream-impl.h>
21 #include <dali/integration-api/debug.h>
26 #include <dali/integration-api/adaptor-framework/android/android-framework.h>
27 #include <dali/internal/adaptor-framework/common/file-loader-impl.h>
31 FileStream::Impl::Impl(const std::string& filename, uint8_t mode)
32 : mFileName(filename),
38 DALI_ASSERT_DEBUG(!filename.empty() && "Can't open a empty filename.");
39 DALI_ASSERT_DEBUG(mode != 0 && "No mode is undefined behaviour");
42 FileStream::Impl::Impl(uint8_t* buffer, size_t dataSize, uint8_t mode)
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.");
53 FileStream::Impl::Impl(Dali::Vector<uint8_t>& buffer, size_t dataSize, uint8_t mode)
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).
66 buffer.Resize(mDataSize);
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.");
74 FileStream::Impl::~Impl()
78 const int closeFailed = fclose(mFile);
81 DALI_LOG_WARNING("File close failed for FILE: \"%p\".\n", static_cast<void*>(mFile));
87 if(mFileStream.is_open())
93 std::iostream& FileStream::Impl::GetStream()
97 // return empty stream if FILE stream is open to avoid simultaneous access to the same file
101 if(mFileStream.is_open())
106 if(mBufferStream.rdbuf()->in_avail())
108 return mBufferStream;
113 if(mMode & Dali::FileStream::APPEND)
115 openMode |= (std::ios::out | std::ios::app);
117 else if(mMode & Dali::FileStream::WRITE)
119 openMode |= (std::ios::out | std::ios::ate);
122 if(mMode & Dali::FileStream::READ)
124 openMode |= std::ios::in;
127 if(mMode & Dali::FileStream::BINARY)
129 openMode |= std::ios::binary;
132 if(!mFileName.empty())
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))
137 std::streampos fileSize;
138 if(ReadFile(mFileName, fileSize, mFileBuffer, Dali::FileLoader::TEXT))
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())
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));
150 return mBufferStream;
154 DALI_LOG_ERROR("stream open failed for: \"%s\", in mode: \"%d\".\n", mFileName.c_str(), static_cast<int>(openMode));
159 mFileStream.open(mFileName, static_cast<std::ios_base::openmode>(openMode));
160 if(!mFileStream.is_open())
162 DALI_LOG_ERROR("stream open failed for: \"%s\", in mode: \"%d\".\n", mFileName.c_str(), static_cast<int>(openMode));
169 mBufferStream.rdbuf()->pubsetbuf(reinterpret_cast<char*>(mBuffer), mDataSize);
170 if(!mBufferStream.rdbuf()->in_avail())
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));
179 return mBufferStream;
182 FILE* FileStream::Impl::GetFile()
184 if(mFileStream.is_open() || mBufferStream.rdbuf()->in_avail())
186 // return empty FILE stream if the stream is open to avoid simultaneous access to the same file
195 char openMode[16] = {0};
198 if(mMode & Dali::FileStream::APPEND)
202 else if(mMode & Dali::FileStream::WRITE)
211 if(mMode & Dali::FileStream::BINARY)
218 if(!mFileName.empty())
220 if(!(mMode & Dali::FileStream::WRITE) && !(mMode & Dali::FileStream::APPEND))
222 std::streampos fileSize;
223 if(ReadFile(mFileName, fileSize, mFileBuffer, (mMode & Dali::FileStream::BINARY) ? Dali::FileLoader::BINARY : Dali::FileLoader::TEXT))
225 mBuffer = reinterpret_cast<uint8_t*>(&mFileBuffer[0]);
226 mDataSize = fileSize;
227 mFile = fmemopen(mBuffer, mDataSize, openMode);
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),
238 DALI_LOG_ERROR("read file failed for: \"%s\", in mode: \"%s\".\n", mFileName.c_str(), openMode);
243 mFile = fopen(mFileName.c_str(), openMode);
246 DALI_LOG_ERROR("file open failed for: \"%s\", in mode: \"%s\".\n", mFileName.c_str(), openMode);
252 mFile = fmemopen(mBuffer, mDataSize, openMode);
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),