2 * Copyright (c) 2019 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>
23 #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>
32 FileStream::Impl::Impl(const std::string& filename, uint8_t mode)
33 : mFileName( filename ),
39 DALI_ASSERT_DEBUG( !filename.empty() && "Can't open a empty filename." );
40 DALI_ASSERT_DEBUG( mode != 0 && "No mode is undefined behaviour" );
43 FileStream::Impl::Impl(uint8_t* buffer, size_t dataSize, uint8_t mode)
46 mDataSize( dataSize ),
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." );
54 FileStream::Impl::Impl(Dali::Vector<uint8_t>& buffer, size_t dataSize, uint8_t mode)
57 mDataSize( dataSize ),
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).
67 buffer.Resize( mDataSize );
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." );
75 FileStream::Impl::~Impl()
79 const int closeFailed = fclose( mFile );
82 DALI_LOG_WARNING( "File close failed for FILE: \"%p\".\n", static_cast<void*>( mFile ) );
88 if( mFileStream.is_open() )
94 std::iostream& FileStream::Impl::GetStream()
98 // return empty stream if FILE stream is open to avoid simultaneous access to the same file
102 if( mFileStream.is_open() )
107 if( mBufferStream.rdbuf()->in_avail() )
109 return mBufferStream;
114 if( mMode & Dali::FileStream::APPEND )
116 openMode |= ( std::ios::out | std::ios::app );
118 else if( mMode & Dali::FileStream::WRITE )
120 openMode |= ( std::ios::out | std::ios::ate );
123 if( mMode & Dali::FileStream::READ )
125 openMode |= std::ios::in;
128 if( mMode & Dali::FileStream::BINARY )
130 openMode |= std::ios::binary;
133 if( !mFileName.empty() )
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 ) )
138 std::streampos fileSize;
139 if( ReadFile( mFileName, fileSize, mFileBuffer, Dali::FileLoader::TEXT ) )
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() )
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 ) );
149 return mBufferStream;
153 DALI_LOG_ERROR( "stream open failed for: \"%s\", in mode: \"%d\".\n", mFileName.c_str(), static_cast<int>( openMode ) );
158 mFileStream.open( mFileName, static_cast<std::ios_base::openmode>( openMode ) );
159 if( !mFileStream.is_open() )
161 DALI_LOG_ERROR( "stream open failed for: \"%s\", in mode: \"%d\".\n", mFileName.c_str(), static_cast<int>( openMode ) );
168 mBufferStream.rdbuf()->pubsetbuf( reinterpret_cast<char*>( mBuffer ), mDataSize );
169 if( !mBufferStream.rdbuf()->in_avail() )
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 ) );
176 return mBufferStream;
179 FILE* FileStream::Impl::GetFile()
181 if( mFileStream.is_open() || mBufferStream.rdbuf()->in_avail() )
183 // return empty FILE stream if the stream is open to avoid simultaneous access to the same file
192 char openMode[16] = { 0 };
195 if( mMode & Dali::FileStream::APPEND )
199 else if( mMode & Dali::FileStream::WRITE )
208 if( mMode & Dali::FileStream::BINARY )
215 if( !mFileName.empty() )
217 if ( !( mMode & Dali::FileStream::WRITE ) && !( mMode & Dali::FileStream::APPEND ) )
219 std::streampos fileSize;
220 if ( ReadFile( mFileName, fileSize, mFileBuffer, ( mMode & Dali::FileStream::BINARY ) ? Dali::FileLoader::BINARY : Dali::FileLoader::TEXT ) )
222 mBuffer = reinterpret_cast<uint8_t*>( &mFileBuffer[0] );
223 mDataSize = fileSize;
224 mFile = fmemopen( mBuffer, mDataSize, openMode );
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 );
233 DALI_LOG_ERROR( "read file failed for: \"%s\", in mode: \"%s\".\n", mFileName.c_str(), openMode );
238 mFile = fopen( mFileName.c_str(), openMode );
241 DALI_LOG_ERROR( "file open failed for: \"%s\", in mode: \"%s\".\n", mFileName.c_str(), openMode );
247 mFile = fmemopen( mBuffer, mDataSize, openMode );
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 );