Dali 3D User Interface Engine
resource-loader.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 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 
18 // CLASS HEADER
19 #include "resource-loader.h"
20 
21 // EXTERNAL HEADERS
22 #include <iostream>
23 #include <fstream>
24 #include <queue>
25 #include <cstring>
28 
29 // INTERNAL HEADERS
39 
40 using namespace Dali::Integration;
41 
42 namespace Dali
43 {
44 
45 namespace TizenPlatform
46 {
47 
49 {
50  typedef std::pair<ResourceId, ResourceRequest> RequestStorePair;
51  typedef std::map<ResourceId, ResourceRequest> RequestStore;
52  typedef RequestStore::iterator RequestStoreIter;
53 
54  typedef std::queue<LoadedResource> LoadedQueue;
55  typedef std::queue<FailedResource> FailedQueue;
56 
57  typedef std::pair<ResourceTypeId, ResourceRequesterBase*> RequestHandlerPair;
58  typedef std::map<ResourceTypeId, ResourceRequesterBase*> RequestHandlers;
59  typedef RequestHandlers::iterator RequestHandlersIter;
60 
64 
67 
69  {
70  mRequestHandlers.insert(std::make_pair(ResourceBitmap, new ResourceBitmapRequester(*loader)));
71  }
72 
74  {
75  // Delete resource handlers
76  for( RequestHandlersIter it = mRequestHandlers.begin(); it != mRequestHandlers.end(); ++it )
77  {
78  ResourceRequesterBase* requestBase = it->second;
79  delete requestBase;
80  }
81  }
82 
83  void Pause()
84  {
85  // Pause all the request handlers:
86  for( RequestHandlersIter it = mRequestHandlers.begin(), end = mRequestHandlers.end(); it != end; ++it )
87  {
88  ResourceRequesterBase * const requester = it->second;
89  if( requester )
90  {
91  requester->Pause();
92  }
93  }
94  }
95 
96  void Resume()
97  {
98  // Wake up all the request handlers:
99  for( RequestHandlersIter it = mRequestHandlers.begin(), end = mRequestHandlers.end(); it != end; ++it )
100  {
101  ResourceRequesterBase * const requester = it->second;
102  if( requester )
103  {
104  requester->Resume();
105  }
106  }
107  }
108 
109  ResourceRequesterBase* GetRequester(ResourceTypeId typeId)
110  {
111  ResourceRequesterBase* requestHandler = NULL;
112  RequestHandlersIter iter = mRequestHandlers.find(typeId);
113  if(iter != mRequestHandlers.end())
114  {
115  requestHandler = iter->second;
116  }
117  DALI_ASSERT_DEBUG(requestHandler && "All resource types should have a requester defined for them.");
118  return requestHandler;
119  }
120 
121  void LoadResource(const ResourceRequest& request)
122  {
123  // Store resource request for partial loaders. Will get cleaned up after load complete has finished
124  StoreRequest(request);
125 
126  ResourceRequesterBase* requester = GetRequester(request.GetType()->id);
127  if( requester )
128  {
129  ResourceRequest* storedRequest = GetRequest(request.GetId());
130  if( storedRequest != NULL )
131  {
132  requester->LoadResource(*storedRequest); // Pass in stored request
133  }
134  }
135  else
136  {
137  DALI_LOG_ERROR( "Unknown resource type (%u) with path \"%s\" in load request.\n", request.GetType()->id, request.GetPath().c_str() );
138  DALI_ASSERT_DEBUG( 0 == "Unknown resource type in load request at " __FILE__ ".\n" );
139  }
140  }
141 
142  void CancelLoad(ResourceId id, ResourceTypeId typeId)
143  {
144  ResourceRequesterBase* requester = GetRequester(typeId);
145  if( requester )
146  {
147  requester->CancelLoad( id, typeId );
148  }
149  ClearRequest( id );
150  }
151 
152  LoadStatus LoadFurtherResources( LoadedResource partialResource )
153  {
154  LoadStatus loadStatus = RESOURCE_LOADING;
155  RequestStoreIter iter = mStoredRequests.find(partialResource.id);
156 
157  if( mStoredRequests.end() != iter ) // else cancelled. Ignore response
158  {
159  ResourceRequest& request = iter->second;
160  ResourceRequesterBase* requester = GetRequester(request.GetType()->id);
161  if( requester )
162  {
163  loadStatus = requester->LoadFurtherResources( request, partialResource );
164  }
165 
166  DALI_LOG_INFO(gLoaderFilter, Debug::General, "ResourceLoader::LoadFurtherResources( ID:%u complete: %s)\n", request.GetId(), loadStatus==RESOURCE_LOADING?"Loading":loadStatus==RESOURCE_PARTIALLY_LOADED?"PARTIAL":"COMPLETE" );
167  }
168 
169  if( loadStatus == RESOURCE_COMPLETELY_LOADED )
170  {
171  ClearRequest( partialResource.id );
172  }
173 
174  return loadStatus;
175  }
176 
177  void GetResources(ResourceCache& cache)
178  {
179  // Fill the resource cache
180 
181  Mutex::ScopedLock lock( mQueueMutex );
182 
183  // iterate through the successfully loaded resources
184  while (!mLoadedQueue.empty())
185  {
186  LoadedResource loaded( mLoadedQueue.front() );
187  mLoadedQueue.pop();
188  ClearRequest( loaded.id );
189  cache.LoadResponse( loaded.id, loaded.type, loaded.resource, RESOURCE_COMPLETELY_LOADED );
190  }
191 
192  // iterate through the resources which failed to load
193  while (!mFailedLoads.empty())
194  {
195  FailedResource failed(mFailedLoads.front());
196  mFailedLoads.pop();
197  ClearRequest(failed.id);
198  cache.LoadFailed(failed.id, failed.failureType);
199  }
200  }
201 
202  void AddLoadedResource(LoadedResource& resource)
203  {
204  // Lock the LoadedQueue to store the loaded resource
205  Mutex::ScopedLock lock( mQueueMutex );
206 
207  mLoadedQueue.push( resource );
208  }
209 
210  void AddFailedLoad(FailedResource& resource)
211  {
212  // Lock the FailedQueue to store the failed resource information
213  Mutex::ScopedLock lock( mQueueMutex );
214 
215  mFailedLoads.push(resource);
216  }
217 
218  void StoreRequest( const ResourceRequest& request )
219  {
220  DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader: StoreRequest(id:%u)\n", request.GetId());
221  mStoredRequests.insert( RequestStorePair( request.GetId(), request ) ); // copy request as value type
222  }
223 
224  ResourceRequest* GetRequest( ResourceId id )
225  {
226  ResourceRequest* found(NULL);
227  DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader: GetRequest(id:%u)\n", id);
228  RequestStoreIter iter = mStoredRequests.find( id );
229  if( mStoredRequests.end() != iter )
230  {
231  found = &iter->second;
232  }
233  return found;
234  }
235 
236  void ClearRequest( ResourceId resourceId )
237  {
238  DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader: ClearRequest(id:%u)\n", resourceId);
239  RequestStoreIter iter = mStoredRequests.find( resourceId );
240  if( mStoredRequests.end() != iter ) // Can't assert here - cancel load may cross with load failed
241  {
242  mStoredRequests.erase( iter );
243  }
244  }
245 };
246 
247 /********************************************************************************/
248 /**************************** RESOURCE LOADER METHODS ************************/
249 /********************************************************************************/
250 ResourceLoader::ResourceLoader()
251 : mTerminateThread(0)
252 {
253  mImpl = new ResourceLoaderImpl( this );
254 }
255 
257 {
258  // Flag that the ResourceLoader is exiting
259  (void)__sync_or_and_fetch( &mTerminateThread, -1 );
260 
261  delete mImpl;
262 }
263 
265 {
266  mImpl->Pause();
267 }
268 
270 {
271  mImpl->Resume();
272 }
273 
275 {
276  return __sync_fetch_and_or( &mTerminateThread, 0 );
277 }
278 
280 {
281  mImpl->GetResources( cache );
282 }
283 
284 /********************************************************************************/
285 /************************** CALLED FROM LOADER THREADS **********************/
286 /********************************************************************************/
287 
289 {
290  mImpl->AddLoadedResource( resource );
291 }
292 
294 {
295  mImpl->AddFailedLoad( resource );
296 }
297 
298 /********************************************************************************/
299 /********************* CALLED FROM PLATFORM ABSTRACTION **********************/
300 /********************************************************************************/
301 
303 {
304  mImpl->LoadResource(request);
305 }
306 
308 {
309  mImpl->CancelLoad(id, typeId);
310 }
311 
312 bool ResourceLoader::LoadFile( const std::string& filename, std::vector< unsigned char >& buffer ) const
313 {
315  const bool result = LoadFile( filename, daliVec );
316  buffer.resize( daliVec.Size() );
317  memcpy( &buffer[0], &daliVec[0], daliVec.Size() );
318  return result;
319 }
320 
321 bool ResourceLoader::LoadFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const
322 {
323  DALI_LOG_TRACE_METHOD(gLoaderFilter);
324 
325  DALI_ASSERT_DEBUG( 0 != filename.length());
326 
327  bool result;
328 
329  std::filebuf buf;
330  buf.open(filename.c_str(), std::ios::in | std::ios::binary);
331  if( buf.is_open() )
332  {
333  std::istream stream(&buf);
334 
335  // determine data length
336  stream.seekg(0, std::ios_base::end);
337  unsigned int length = static_cast<unsigned int>( stream.tellg() );
338  stream.seekg(0, std::ios_base::beg);
339 
340  // allocate a buffer
341  buffer.Resize(length);
342  // read data into buffer
343  stream.read(reinterpret_cast<char*>(buffer.Begin()), length);
344 
345  DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::LoadFile(%s) - loaded %d bytes\n", filename.c_str(), length);
346 
347  result = true;
348  }
349  else
350  {
351  DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::LoadFile(%s) - failed to load\n", filename.c_str());
352  result = false;
353  }
354 
355  return result;
356 }
357 
358 std::string ResourceLoader::LoadFile(const std::string& filename) const
359 {
360  DALI_LOG_TRACE_METHOD(gLoaderFilter);
361 
362  DALI_ASSERT_DEBUG( 0 != filename.length());
363 
364  std::string contents;
365 
366  std::filebuf buf;
367  buf.open(filename.c_str(), std::ios::in);
368  if( buf.is_open() )
369  {
370  std::istream stream(&buf);
371 
372  // determine data length
373  stream.seekg(0, std::ios_base::end);
374  unsigned int length = static_cast<unsigned int>( stream.tellg() );
375  stream.seekg(0, std::ios_base::beg);
376 
377  // allocate a buffer
378  contents.resize(length);
379  // read data into buffer
380  stream.read(&contents[0], length);
381 
382  DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::LoadFile(%s) - loaded %d bytes\n", filename.c_str(), length);
383  }
384  else
385  {
386  DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::LoadFile(%s) - failed to load\n", filename.c_str());
387  }
388 
389  return contents;
390 }
391 
392 bool ResourceLoader::SaveFile(const std::string& filename, const unsigned char * buffer, unsigned int numBytes )
393 {
394  DALI_LOG_TRACE_METHOD(gLoaderFilter);
395 
396  DALI_ASSERT_DEBUG( 0 != filename.length());
397 
398  bool result = false;
399 
400  std::filebuf buf;
401  buf.open(filename.c_str(), std::ios::out | std::ios_base::trunc | std::ios::binary);
402  if( buf.is_open() )
403  {
404  std::ostream stream(&buf);
405 
406  // determine size of buffer
407  int length = static_cast<int>(numBytes);
408 
409  // write contents of buffer to the file
410  stream.write(reinterpret_cast<const char*>(buffer), length);
411 
412  if( !stream.bad() )
413  {
414  DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::SaveFile(%s) - wrote %d bytes\n", filename.c_str(), length);
415  result = true;
416  }
417  }
418 
419 #if defined(DEBUG_BUILD)
420  if( !result )
421  {
422  DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::SaveFile(%s) - failed to load\n", filename.c_str());
423  }
424 #endif
425 
426  return result;
427 }
428 
429 } // namespace TizenPlatform
430 
431 } // namespace Dali
Dali Docs Home
Read more about Dali