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

Generated by: LCOV version 1.11