LCOV - code coverage report
Current view: top level - framework/source/accelerators - storageholder.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 0 251 0.0 %
Date: 2014-04-14 Functions: 0 21 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <accelerators/storageholder.hxx>
      21             : 
      22             : #include <services.h>
      23             : 
      24             : #include <com/sun/star/container/NoSuchElementException.hpp>
      25             : 
      26             : #include <com/sun/star/container/XNameAccess.hpp>
      27             : 
      28             : #include <com/sun/star/beans/XPropertySet.hpp>
      29             : 
      30             : #include <com/sun/star/embed/ElementModes.hpp>
      31             : 
      32             : #include <com/sun/star/embed/XTransactedObject.hpp>
      33             : 
      34             : #include <com/sun/star/embed/XPackageStructureCreator.hpp>
      35             : 
      36             : #include <com/sun/star/lang/XSingleServiceFactory.hpp>
      37             : 
      38             : #include <com/sun/star/io/XSeekable.hpp>
      39             : 
      40             : #define PATH_SEPARATOR_ASCII        "/"
      41             : #define PATH_SEPARATOR_UNICODE      ((sal_Unicode)'/')
      42             : #define PATH_SEPARATOR              OUString(PATH_SEPARATOR_ASCII)
      43             : 
      44             : namespace framework
      45             : {
      46             : 
      47           0 : StorageHolder::StorageHolder()
      48             : {
      49           0 : }
      50             : 
      51           0 : StorageHolder::~StorageHolder()
      52             : {
      53             :     // TODO implement me
      54             :     // dispose/clear etcpp.
      55           0 : }
      56             : 
      57           0 : void StorageHolder::forgetCachedStorages()
      58             : {
      59           0 :     osl::MutexGuard g(m_mutex);
      60           0 :     TPath2StorageInfo::iterator pIt;
      61           0 :     for (  pIt  = m_lStorages.begin();
      62           0 :            pIt != m_lStorages.end();
      63             :          ++pIt                       )
      64             :     {
      65           0 :         TStorageInfo& rInfo = pIt->second;
      66             :         // TODO think about listener !
      67           0 :         rInfo.Storage.clear();
      68             :     }
      69           0 :     m_lStorages.clear();
      70           0 : }
      71             : 
      72           0 : void StorageHolder::setRootStorage(const css::uno::Reference< css::embed::XStorage >& xRoot)
      73             : {
      74           0 :     osl::MutexGuard g(m_mutex);
      75           0 :     m_xRoot = xRoot;
      76           0 : }
      77             : 
      78           0 : css::uno::Reference< css::embed::XStorage > StorageHolder::getRootStorage() const
      79             : {
      80           0 :     osl::MutexGuard g(m_mutex);
      81           0 :     return m_xRoot;
      82             : }
      83             : 
      84           0 : css::uno::Reference< css::embed::XStorage > StorageHolder::openPath(const OUString& sPath    ,
      85             :                                                                           sal_Int32        nOpenMode)
      86             : {
      87           0 :     OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
      88           0 :     OUStringList    lFolders    = StorageHolder::impl_st_parsePath(sNormedPath);
      89             : 
      90             :     // SAFE -> ----------------------------------
      91           0 :     osl::ResettableMutexGuard aReadLock(m_mutex);
      92           0 :     css::uno::Reference< css::embed::XStorage > xParent = m_xRoot;
      93           0 :     aReadLock.clear();
      94             :     // <- SAFE ----------------------------------
      95             : 
      96           0 :     css::uno::Reference< css::embed::XStorage > xChild;
      97           0 :     OUString                             sRelPath;
      98           0 :     OUStringList::const_iterator                pIt;
      99             : 
     100           0 :     for (  pIt  = lFolders.begin();
     101           0 :            pIt != lFolders.end();
     102             :          ++pIt                    )
     103             :     {
     104           0 :         const OUString& sChild     = *pIt;
     105           0 :               OUString  sCheckPath (sRelPath);
     106           0 :                                sCheckPath += sChild;
     107           0 :                                sCheckPath += PATH_SEPARATOR;
     108             : 
     109             :         // SAFE -> ------------------------------
     110           0 :         aReadLock.reset();
     111             : 
     112             :         // If we found an already open storage ... we must increase
     113             :         // its use count. Otherwhise it will may be closed to early :-)
     114           0 :         TPath2StorageInfo::iterator pCheck = m_lStorages.find(sCheckPath);
     115           0 :         TStorageInfo*               pInfo  = 0;
     116           0 :         if (pCheck != m_lStorages.end())
     117             :         {
     118           0 :             pInfo = &(pCheck->second);
     119           0 :             ++(pInfo->UseCount);
     120           0 :             xChild = pInfo->Storage;
     121             : 
     122           0 :             aReadLock.clear();
     123             :             // <- SAFE ------------------------------
     124             :         }
     125             :         else
     126             :         {
     127           0 :             aReadLock.clear();
     128             :             // <- SAFE ------------------------------
     129             : 
     130             :             try
     131             :             {
     132           0 :                 xChild = StorageHolder::openSubStorageWithFallback(xParent, sChild, nOpenMode, true); // TODO think about delegating fallback decision to our own calli!
     133             :             }
     134           0 :             catch(const css::uno::RuntimeException&)
     135           0 :                 { throw; }
     136           0 :             catch(const css::uno::Exception&)
     137             :                 {
     138             :                     /* TODO URGENT!
     139             :                         in case we found some "already existing storages" on the path before and increased its UseCount ...
     140             :                         and now we will get an exception on creating a new sub storage ...
     141             :                         we must decrease all UseCounts, which was touched before. Otherwise these storages cant be closed!
     142             : 
     143             :                         Idea: Using of another structure member "PossibleUseCount" as vector of unique numbers.
     144             :                         Every thread use another unique number to identify all "owned candidates".
     145             :                         A flush method with the same unique number force increasing of the "UseCount" variable then
     146             :                         inside a synchronized block ...
     147             :                     */
     148           0 :                     throw;
     149             :                 }
     150             : 
     151           0 :             osl::MutexGuard g(m_mutex);
     152           0 :             pInfo = &(m_lStorages[sCheckPath]);
     153           0 :             pInfo->Storage  = xChild;
     154           0 :             pInfo->UseCount = 1;
     155             :         }
     156             : 
     157           0 :         xParent   = xChild;
     158           0 :         sRelPath += sChild;
     159           0 :         sRelPath += PATH_SEPARATOR;
     160           0 :     }
     161             : 
     162             :     // TODO think about return last storage as working storage ... but dont caching it inside this holder!
     163             :     // => otherwise the same storage is may be commit more then once.
     164             : 
     165           0 :     return xChild;
     166             : }
     167             : 
     168           0 : StorageHolder::TStorageList StorageHolder::getAllPathStorages(const OUString& sPath)
     169             : {
     170           0 :     OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
     171           0 :     OUStringList    lFolders    = StorageHolder::impl_st_parsePath(sNormedPath);
     172             : 
     173           0 :     StorageHolder::TStorageList  lStoragesOfPath;
     174           0 :     OUString              sRelPath;
     175           0 :     OUStringList::const_iterator pIt;
     176             : 
     177           0 :     osl::MutexGuard g(m_mutex);
     178             : 
     179           0 :     for (  pIt  = lFolders.begin();
     180           0 :            pIt != lFolders.end();
     181             :          ++pIt                    )
     182             :     {
     183           0 :         const OUString& sChild     = *pIt;
     184           0 :               OUString  sCheckPath (sRelPath);
     185           0 :                                sCheckPath += sChild;
     186           0 :                                sCheckPath += PATH_SEPARATOR;
     187             : 
     188           0 :         TPath2StorageInfo::iterator pCheck = m_lStorages.find(sCheckPath);
     189           0 :         if (pCheck == m_lStorages.end())
     190             :         {
     191             :             // at least one path element was not found
     192             :             // Seems that this path isnt open ...
     193           0 :             lStoragesOfPath.clear();
     194           0 :             return lStoragesOfPath;
     195             :         }
     196             : 
     197           0 :         TStorageInfo& rInfo = pCheck->second;
     198           0 :         lStoragesOfPath.push_back(rInfo.Storage);
     199             : 
     200           0 :         sRelPath += sChild;
     201           0 :         sRelPath += PATH_SEPARATOR;
     202           0 :     }
     203             : 
     204           0 :     return lStoragesOfPath;
     205             : }
     206             : 
     207           0 : void StorageHolder::commitPath(const OUString& sPath)
     208             : {
     209           0 :     StorageHolder::TStorageList lStorages = getAllPathStorages(sPath);
     210             : 
     211           0 :     css::uno::Reference< css::embed::XTransactedObject > xCommit;
     212           0 :     StorageHolder::TStorageList::reverse_iterator pIt;
     213           0 :     for (  pIt  = lStorages.rbegin(); // order of commit is important ... otherwise changes are not recognized!
     214           0 :            pIt != lStorages.rend();
     215             :          ++pIt                      )
     216             :     {
     217           0 :         xCommit = css::uno::Reference< css::embed::XTransactedObject >(*pIt, css::uno::UNO_QUERY);
     218           0 :         if (!xCommit.is())
     219           0 :             continue;
     220           0 :         xCommit->commit();
     221             :     }
     222             : 
     223             :     // SAFE -> ------------------------------
     224           0 :     osl::ClearableMutexGuard aReadLock(m_mutex);
     225           0 :     xCommit = css::uno::Reference< css::embed::XTransactedObject >(m_xRoot, css::uno::UNO_QUERY);
     226           0 :     aReadLock.clear();
     227             :     // <- SAFE ------------------------------
     228             : 
     229           0 :     if (xCommit.is())
     230           0 :         xCommit->commit();
     231           0 : }
     232             : 
     233           0 : void StorageHolder::closePath(const OUString& rPath)
     234             : {
     235           0 :     OUString sNormedPath = StorageHolder::impl_st_normPath(rPath);
     236           0 :     OUStringList    lFolders    = StorageHolder::impl_st_parsePath(sNormedPath);
     237             : 
     238             :     /* convert list of paths in the following way:
     239             :         [0] = "path_1" => "path_1
     240             :         [1] = "path_2" => "path_1/path_2"
     241             :         [2] = "path_3" => "path_1/path_2/path_3"
     242             :     */
     243           0 :     OUStringList::iterator pIt1;
     244           0 :     OUString        sParentPath;
     245           0 :     for (  pIt1  = lFolders.begin();
     246           0 :            pIt1 != lFolders.end();
     247             :          ++pIt1                    )
     248             :     {
     249           0 :         OUString sCurrentRelPath  = sParentPath;
     250           0 :                         sCurrentRelPath += *pIt1;
     251           0 :                         sCurrentRelPath += PATH_SEPARATOR;
     252           0 :         *pIt1       = sCurrentRelPath;
     253           0 :         sParentPath = sCurrentRelPath;
     254           0 :     }
     255             : 
     256           0 :     osl::MutexGuard g(m_mutex);
     257             : 
     258           0 :     OUStringList::reverse_iterator pIt2;
     259           0 :     for (  pIt2  = lFolders.rbegin();
     260           0 :            pIt2 != lFolders.rend();
     261             :          ++pIt2                     )
     262             :     {
     263           0 :         OUString             sPath = *pIt2;
     264           0 :         TPath2StorageInfo::iterator pPath = m_lStorages.find(sPath);
     265           0 :         if (pPath == m_lStorages.end())
     266           0 :             continue; // ???
     267             : 
     268           0 :         TStorageInfo& rInfo = pPath->second;
     269           0 :         --rInfo.UseCount;
     270           0 :         if (rInfo.UseCount < 1)
     271             :         {
     272           0 :             rInfo.Storage.clear();
     273           0 :             m_lStorages.erase(pPath);
     274             :         }
     275           0 :     }
     276           0 : }
     277             : 
     278           0 : void StorageHolder::notifyPath(const OUString& sPath)
     279             : {
     280           0 :     OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
     281             : 
     282           0 :     osl::MutexGuard g(m_mutex);
     283             : 
     284           0 :     TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath);
     285           0 :     if (pIt1 == m_lStorages.end())
     286           0 :         return;
     287             : 
     288           0 :     TStorageInfo& rInfo = pIt1->second;
     289           0 :     TStorageListenerList::iterator pIt2;
     290           0 :     for (  pIt2  = rInfo.Listener.begin();
     291           0 :            pIt2 != rInfo.Listener.end();
     292             :          ++pIt2                          )
     293             :     {
     294           0 :         IStorageListener* pListener = *pIt2;
     295           0 :         if (pListener)
     296           0 :             pListener->changesOccurred(sNormedPath);
     297           0 :     }
     298             : }
     299             : 
     300           0 : void StorageHolder::addStorageListener(      IStorageListener* pListener,
     301             :                                        const OUString&  sPath    )
     302             : {
     303           0 :     OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
     304             : 
     305           0 :     osl::MutexGuard g(m_mutex);
     306             : 
     307           0 :     TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath);
     308           0 :     if (pIt1 == m_lStorages.end())
     309           0 :         return;
     310             : 
     311           0 :     TStorageInfo& rInfo = pIt1->second;
     312           0 :     TStorageListenerList::iterator pIt2 = ::std::find(rInfo.Listener.begin(), rInfo.Listener.end(), pListener);
     313           0 :     if (pIt2 == rInfo.Listener.end())
     314           0 :         rInfo.Listener.push_back(pListener);
     315             : }
     316             : 
     317           0 : void StorageHolder::removeStorageListener(      IStorageListener* pListener,
     318             :                                           const OUString&  sPath    )
     319             : {
     320           0 :     OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
     321             : 
     322           0 :     osl::MutexGuard g(m_mutex);
     323             : 
     324           0 :     TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath);
     325           0 :     if (pIt1 == m_lStorages.end())
     326           0 :         return;
     327             : 
     328           0 :     TStorageInfo& rInfo = pIt1->second;
     329           0 :     TStorageListenerList::iterator pIt2 = ::std::find(rInfo.Listener.begin(), rInfo.Listener.end(), pListener);
     330           0 :     if (pIt2 != rInfo.Listener.end())
     331           0 :         rInfo.Listener.erase(pIt2);
     332             : }
     333             : 
     334           0 : OUString StorageHolder::getPathOfStorage(const css::uno::Reference< css::embed::XStorage >& xStorage)
     335             : {
     336           0 :     osl::MutexGuard g(m_mutex);
     337             : 
     338           0 :     TPath2StorageInfo::const_iterator pIt;
     339           0 :     for (  pIt  = m_lStorages.begin();
     340           0 :            pIt != m_lStorages.end();
     341             :          ++pIt                       )
     342             :     {
     343           0 :         const TStorageInfo& rInfo = pIt->second;
     344           0 :         if (rInfo.Storage == xStorage)
     345           0 :             break;
     346             :     }
     347             : 
     348           0 :     if (pIt == m_lStorages.end())
     349           0 :         return OUString();
     350             : 
     351           0 :     return pIt->first;
     352             : }
     353             : 
     354           0 : css::uno::Reference< css::embed::XStorage > StorageHolder::getParentStorage(const css::uno::Reference< css::embed::XStorage >& xChild)
     355             : {
     356           0 :     OUString sChildPath = getPathOfStorage(xChild);
     357           0 :     return getParentStorage(sChildPath);
     358             : }
     359             : 
     360           0 : css::uno::Reference< css::embed::XStorage > StorageHolder::getParentStorage(const OUString& sChildPath)
     361             : {
     362             :     // normed path = "a/b/c/" ... we search for "a/b/"
     363           0 :     OUString sNormedPath = StorageHolder::impl_st_normPath(sChildPath);
     364           0 :     OUStringList    lFolders    = StorageHolder::impl_st_parsePath(sNormedPath);
     365           0 :     sal_Int32       c           = lFolders.size();
     366             : 
     367             :     // a) ""       => -       => no parent
     368             :     // b) "a/b/c/" => "a/b/"  => return storage "a/b/"
     369             :     // c) "a/"     => ""      => return root !
     370             : 
     371             :     // a)
     372           0 :     if (c < 1)
     373           0 :         return css::uno::Reference< css::embed::XStorage >();
     374             : 
     375             :     // SAFE -> ----------------------------------
     376           0 :     osl::ClearableMutexGuard aReadLock(m_mutex);
     377             : 
     378             :     // b)
     379           0 :     if (c < 2)
     380           0 :         return m_xRoot;
     381             : 
     382             :     // c)
     383           0 :     OUString sParentPath;
     384           0 :     sal_Int32       i = 0;
     385           0 :     for (i=0; i<c-1; ++i)
     386             :     {
     387           0 :         sParentPath += lFolders[i];
     388           0 :         sParentPath += PATH_SEPARATOR;
     389             :     }
     390             : 
     391           0 :     TPath2StorageInfo::const_iterator pParent = m_lStorages.find(sParentPath);
     392           0 :     if (pParent != m_lStorages.end())
     393           0 :         return pParent->second.Storage;
     394             : 
     395           0 :     aReadLock.clear();
     396             :     // <- SAFE ----------------------------------
     397             : 
     398             :     // ?
     399             :     SAL_INFO("fwk", "StorageHolder::getParentStorage(): Unexpected situation. Cached storage item seems to be wrong.");
     400           0 :     return css::uno::Reference< css::embed::XStorage >();
     401             : }
     402             : 
     403           0 : void StorageHolder::operator=(const StorageHolder& rCopy)
     404             : {
     405           0 :     osl::MutexGuard g(m_mutex);
     406           0 :     m_xRoot     = rCopy.m_xRoot;
     407           0 :     m_lStorages = rCopy.m_lStorages;
     408           0 : }
     409             : 
     410           0 : css::uno::Reference< css::embed::XStorage > StorageHolder::openSubStorageWithFallback(const css::uno::Reference< css::embed::XStorage >& xBaseStorage  ,
     411             :                                                                                       const OUString&                             sSubStorage   ,
     412             :                                                                                             sal_Int32                                    eOpenMode     ,
     413             :                                                                                             bool                                     bAllowFallback)
     414             : {
     415             :     // a) try it first with user specified open mode
     416             :     //    ignore errors ... but save it for later use!
     417           0 :     css::uno::Exception exResult;
     418             :     try
     419             :     {
     420           0 :         css::uno::Reference< css::embed::XStorage > xSubStorage = xBaseStorage->openStorageElement(sSubStorage, eOpenMode);
     421           0 :         if (xSubStorage.is())
     422           0 :             return xSubStorage;
     423             :     }
     424           0 :     catch(const css::uno::RuntimeException&)
     425           0 :         { throw; }
     426           0 :     catch(const css::uno::Exception& ex)
     427           0 :         { exResult = ex; }
     428             : 
     429             :     // b) readonly already tried? => forward last error!
     430           0 :     if (
     431           0 :         (!bAllowFallback                                                                 ) ||   // fallback allowed  ?
     432           0 :         ((eOpenMode & css::embed::ElementModes::WRITE) != css::embed::ElementModes::WRITE)      // fallback possible ?
     433             :        )
     434           0 :         throw exResult;
     435             : 
     436             :     // c) try it readonly
     437             :     //    dont catch exception here! Outside code wish to know, if operation failed or not.
     438             :     //    Otherwhise they work on NULL references ...
     439           0 :     sal_Int32 eNewMode = (eOpenMode & ~css::embed::ElementModes::WRITE);
     440           0 :     css::uno::Reference< css::embed::XStorage > xSubStorage = xBaseStorage->openStorageElement(sSubStorage, eNewMode);
     441           0 :     if (xSubStorage.is())
     442           0 :         return xSubStorage;
     443             : 
     444             :     // d) no chance!
     445             :     SAL_INFO("fwk", "openSubStorageWithFallback(): Unexpected situation! Got no exception for missing storage ...");
     446           0 :     return css::uno::Reference< css::embed::XStorage >();
     447             : }
     448             : 
     449           0 : css::uno::Reference< css::io::XStream > StorageHolder::openSubStreamWithFallback(const css::uno::Reference< css::embed::XStorage >& xBaseStorage  ,
     450             :                                                                                  const OUString&                             sSubStream    ,
     451             :                                                                                        sal_Int32                                    eOpenMode     ,
     452             :                                                                                        bool                                     bAllowFallback)
     453             : {
     454             :     // a) try it first with user specified open mode
     455             :     //    ignore errors ... but save it for later use!
     456           0 :     css::uno::Exception exResult;
     457             :     try
     458             :     {
     459           0 :         css::uno::Reference< css::io::XStream > xSubStream = xBaseStorage->openStreamElement(sSubStream, eOpenMode);
     460           0 :         if (xSubStream.is())
     461           0 :             return xSubStream;
     462             :     }
     463           0 :     catch(const css::uno::RuntimeException&)
     464           0 :         { throw; }
     465           0 :     catch(const css::uno::Exception& ex)
     466           0 :         { exResult = ex; }
     467             : 
     468             :     // b) readonly already tried? => forward last error!
     469           0 :     if (
     470           0 :         (!bAllowFallback                                                                 ) ||   // fallback allowed  ?
     471           0 :         ((eOpenMode & css::embed::ElementModes::WRITE) != css::embed::ElementModes::WRITE)      // fallback possible ?
     472             :        )
     473           0 :         throw exResult;
     474             : 
     475             :     // c) try it readonly
     476             :     //    dont catch exception here! Outside code wish to know, if operation failed or not.
     477             :     //    Otherwhise they work on NULL references ...
     478           0 :     sal_Int32 eNewMode = (eOpenMode & ~css::embed::ElementModes::WRITE);
     479           0 :     css::uno::Reference< css::io::XStream > xSubStream = xBaseStorage->openStreamElement(sSubStream, eNewMode);
     480           0 :     if (xSubStream.is())
     481           0 :         return xSubStream;
     482             : 
     483             :     // d) no chance!
     484             :     SAL_INFO("fwk", "openSubStreamWithFallbacks(): Unexpected situation! Got no exception for missing stream ...");
     485           0 :     return css::uno::Reference< css::io::XStream >();
     486             : }
     487             : 
     488           0 : OUString StorageHolder::impl_st_normPath(const OUString& sPath)
     489             : {
     490             :     // path must start without "/" but end with "/"!
     491             : 
     492           0 :     OUString sNormedPath = sPath;
     493             : 
     494             :     // "/bla" => "bla" && "/" => "" (!)
     495           0 :     if (sNormedPath.startsWith(PATH_SEPARATOR))
     496           0 :         sNormedPath += sNormedPath.copy(1);
     497             : 
     498             :     // "/" => "" || "" => "" ?
     499           0 :     if (sNormedPath.isEmpty())
     500           0 :         return OUString();
     501             : 
     502             :     // "bla" => "bla/"
     503           0 :     if (sNormedPath.lastIndexOf(PATH_SEPARATOR) != (sNormedPath.getLength()-1))
     504           0 :         sNormedPath += PATH_SEPARATOR;
     505             : 
     506           0 :     return sNormedPath;
     507             : }
     508             : 
     509           0 : OUStringList StorageHolder::impl_st_parsePath(const OUString& sPath)
     510             : {
     511           0 :     OUStringList lToken;
     512           0 :     sal_Int32    i  = 0;
     513             :     while (true)
     514             :     {
     515           0 :         OUString sToken = sPath.getToken(0, PATH_SEPARATOR_UNICODE, i);
     516           0 :         if (i < 0)
     517           0 :             break;
     518           0 :         lToken.push_back(sToken);
     519           0 :     }
     520           0 :     return lToken;
     521             : }
     522             : 
     523             : } // namespace framework
     524             : 
     525             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10