LCOV - code coverage report
Current view: top level - src - collectioncollection.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 76 77 98.7 %
Date: 2024-06-15 08:26:09 Functions: 14 15 93.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   Zipios -- a small C++ library that provides easy access to .zip files.
       3             : 
       4             :   Copyright (C) 2000-2007  Thomas Sondergaard
       5             :   Copyright (c) 2015-2022  Made to Order Software Corp.  All Rights Reserved
       6             : 
       7             :   This library is free software; you can redistribute it and/or
       8             :   modify it under the terms of the GNU Lesser General Public
       9             :   License as published by the Free Software Foundation; either
      10             :   version 2.1 of the License, or (at your option) any later version.
      11             : 
      12             :   This library is distributed in the hope that it will be useful,
      13             :   but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :   Lesser General Public License for more details.
      16             : 
      17             :   You should have received a copy of the GNU Lesser General Public
      18             :   License along with this library; if not, write to the Free Software
      19             :   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
      20             : */
      21             : 
      22             : /** \file
      23             :  * \brief Implementation of zipios::CollectionCollection.
      24             :  *
      25             :  * This class derives from zipios::FileCollection. It allows to many
      26             :  * any number of collections within one collection.
      27             :  */
      28             : 
      29             : #include "zipios/collectioncollection.hpp"
      30             : 
      31             : #include "zipios/zipiosexceptions.hpp"
      32             : 
      33             : #include "zipios_common.hpp"
      34             : 
      35             : 
      36             : namespace zipios
      37             : {
      38             : 
      39             : 
      40             : namespace
      41             : {
      42             : 
      43             : /** \brief Search for an entry.
      44             :  *
      45             :  * This function searches for an entry that match the given name.
      46             :  * If that entry exists, the \p it parameter will be pointing
      47             :  * to it.
      48             :  *
      49             :  * The \p cep parameter is also set to the object found.
      50             :  *
      51             :  * \param[in] collections  The collections to search for the specified name.
      52             :  * \param[in] name  The name of the entry to search.
      53             :  * \param[out] cep  The pointer to the entry found.
      54             :  * \param[out] file_collection  A reference to a smarter pointer where we
      55             :  *                              can save the found file collection.
      56             :  * \param[in] matchpath  How the name of the entry is compared with \p name.
      57             :  */
      58        1013 : void matchEntry(
      59             :       CollectionCollection::vector_t collections
      60             :     , std::string const & name
      61             :     , FileEntry::pointer_t & cep
      62             :     , FileCollection::pointer_t & file_collection
      63             :     , CollectionCollection::MatchPath matchpath)
      64             : {
      65        2002 :     for(auto it = collections.begin(); it != collections.end(); ++it)
      66             :     {
      67        1726 :         cep = (*it)->getEntry(name, matchpath);
      68        1726 :         if(cep)
      69             :         {
      70         737 :             file_collection = *it;
      71         737 :             return;
      72             :         }
      73             :     }
      74         276 :     cep.reset();
      75         276 :     file_collection.reset();
      76             : }
      77             : 
      78             : } // no name namespace
      79             : 
      80             : 
      81             : /** \class CollectionCollection
      82             :  * \brief A collection of collections.
      83             :  *
      84             :  * CollectionCollection is a FileCollection that consists of an
      85             :  * arbitrary number of FileCollection's. With a CollectionCollection
      86             :  * the user can use multiple FileCollection objects transparently, making
      87             :  * it easy for a program to keep some of its files in a zip archive and
      88             :  * others stored in ordinary files. CollectionCollection can be used
      89             :  * to create a simple virtual filesystem, where all collections are
      90             :  * mounted on /. If more than one collection contain a file with
      91             :  * the same path only the one in the first added collection is
      92             :  * accessible.
      93             :  */
      94             : 
      95             : 
      96             : 
      97             : /** \brief Initialize a CollectionCollection object.
      98             :  *
      99             :  * The constructor initializes the CollectionCollection as a valid
     100             :  * collection.
     101             :  */
     102          19 : CollectionCollection::CollectionCollection()
     103             : {
     104          19 :     m_valid = true; // we are valid even though we are empty!
     105          19 : }
     106             : 
     107             : 
     108             : /** \brief Copy a CollectionCollection in another.
     109             :  *
     110             :  * This function copies a collection of collections in another. Note
     111             :  * that all the children get cloned so the copy can be edited without
     112             :  * modify the source and vice versa.
     113             :  *
     114             :  * \param[in] rhs  The source to copy in the new CollectionCollection.
     115             :  */
     116          22 : CollectionCollection::CollectionCollection(CollectionCollection const & rhs)
     117          22 :     : FileCollection(rhs)
     118             : {
     119          22 :     m_collections.reserve(rhs.m_collections.size());
     120          51 :     for(auto it = rhs.m_collections.begin(); it != rhs.m_collections.end(); ++it)
     121             :     {
     122          29 :         m_collections.push_back((*it)->clone());
     123             :     }
     124          22 : }
     125             : 
     126             : 
     127             : /** \brief Copy assignment operator.
     128             :  *
     129             :  * This assignment operator copies \p rhs to this collection replacing
     130             :  * the file entries that exist in this collection.
     131             :  *
     132             :  * Note that the source file entries are cloned in the destination so
     133             :  * modifying this collection will not modify the source.
     134             :  *
     135             :  * \param[in] rhs  The source to copy in this collection.
     136             :  */
     137           7 : CollectionCollection & CollectionCollection::operator = (CollectionCollection const & rhs)
     138             : {
     139           7 :     FileCollection::operator = (rhs);
     140             : 
     141           7 :     if(this != &rhs)
     142             :     {
     143           7 :         m_collections.clear();
     144             :         // A call to the CollectionCollection::size() function has side
     145             :         // effects, try to avoid them at this time
     146             :         //m_collections.reserve(rhs.m_collections.size());
     147          11 :         for(auto it = rhs.m_collections.begin(); it != rhs.m_collections.end(); ++it)
     148             :         {
     149           4 :             m_collections.push_back((*it)->clone());
     150             :         }
     151             :     }
     152             : 
     153           7 :     return *this;
     154             : }
     155             : 
     156             : 
     157             : /** \brief Create a clone of this object.
     158             :  *
     159             :  * This function creates a heap allocated clone of the CollectionCollection.
     160             :  *
     161             :  * Note that all the collections that this CollectionCollection points
     162             :  * to are all going to get cloned.
     163             :  *
     164             :  * \return A shared pointer to a copy of this CollectionCollection.
     165             :  */
     166          15 : FileCollection::pointer_t CollectionCollection::clone() const
     167             : {
     168          15 :     return std::make_shared<CollectionCollection>(*this);
     169             : }
     170             : 
     171             : 
     172             : /** \brief Clean up this CollectionCollection object.
     173             :  *
     174             :  * This function ensures that the CollectionCollection object
     175             :  * is cleaned up before deallocating the memory.
     176             :  */
     177          41 : CollectionCollection::~CollectionCollection()
     178             : {
     179          41 :     close();
     180          41 : }
     181             : 
     182             : 
     183             : /** \brief Add a FileCollection to this CollectionCollection.
     184             :  *
     185             :  * This function adds a collection in this CollectionCollection.
     186             :  * Since a CollectionCollection is itself a FileCollection, you
     187             :  * may add a CollectionCollection to another CollectionCollection.
     188             :  *
     189             :  * \note
     190             :  * The FileCollection to be added must be valid or it will be ignored.
     191             :  *
     192             :  * \param[in] collection  The collection to add.
     193             :  *
     194             :  * \return true if the collection was added successfully.
     195             :  *
     196             :  * \sa addCollection(FileCollection::pointer_t collection);
     197             :  */
     198          42 : bool CollectionCollection::addCollection(FileCollection const & collection)
     199             : {
     200          42 :     mustBeValid();
     201             : 
     202             :     /** \TODO
     203             :      * At this time the function verifies that you are not trying to add
     204             :      * a CollectionCollection to itself. However, this test is currently
     205             :      * really weak. We need to check whether any collection in the
     206             :      * input \p collection represents this collection.
     207             :      */
     208          27 :     if(this == &collection || !collection.isValid())
     209             :     {
     210           4 :         return false;
     211             :     }
     212             : 
     213          23 :     m_collections.push_back(collection.clone());
     214             : 
     215          23 :     return true;
     216             : }
     217             : 
     218             : 
     219             : /** \brief Add a collection to this CollectionCollection.
     220             :  *
     221             :  * This function adds the collection pointed to by \p collection to
     222             :  * this CollectionCollection.
     223             :  *
     224             :  * The CollectionCollection makes a clone of the specified \p collection
     225             :  * to make sure management of the child collection works as expected.
     226             :  *
     227             :  * If the collection does not get added, the function returns false.
     228             :  * This happens when the \p collection parameter represents an invalid
     229             :  * collection.
     230             :  *
     231             :  * \exception InvalidException
     232             :  * The function raises InvalidException if the \p collection parameter
     233             :  * is a null pointer.
     234             :  *
     235             :  * \param[in] collection  A pointer to the collection to add.
     236             :  *
     237             :  * \return true if the collection was added successfully.
     238             :  *
     239             :  * \sa addCollection(FileCollection const & collection);
     240             :  */
     241          17 : bool CollectionCollection::addCollection(FileCollection::pointer_t collection)
     242             : {
     243          17 :     if(collection == nullptr)
     244             :     {
     245             :         // TBD: should we return false instead?
     246           1 :         throw InvalidException("CollectionCollection::addCollection(): called with a null collection pointer");
     247             :     }
     248             : 
     249          16 :     return addCollection(*collection);
     250             : }
     251             : 
     252             : 
     253             : /** \brief Close the CollectionCollection object.
     254             :  *
     255             :  * This function marks the collection as invalid in effect rendering
     256             :  * the collection unusable. Note that all the collections that you
     257             :  * previously added to this collection all get marked as invalid
     258             :  * (i.e. their close() function gets called.) This has the nice side
     259             :  * effect to release memory immediately.
     260             :  *
     261             :  * \note
     262             :  * This is different from creating an empty CollectionCollection
     263             :  * which is empty and valid.
     264             :  */
     265          49 : void CollectionCollection::close()
     266             : {
     267             :     // make sure to close all the children first
     268             :     // (although I would imagine that the m_collections.clear() should
     269             :     // be enough, unless someone else has a reference to another one
     270             :     // of the sub-collections--but I do not think one can get such as
     271             :     // reference at this point, remember that the addCollection()
     272             :     // creates a clone of the collection being added.)
     273         105 :     for(auto it = m_collections.begin(); it != m_collections.end(); ++it)
     274             :     {
     275             :         // each collection in the collection must be valid since we
     276             :         // may hit any one of them
     277          56 :         (*it)->close();
     278             :     }
     279          49 :     m_collections.clear();
     280             : 
     281          49 :     FileCollection::close();
     282          49 : }
     283             : 
     284             : 
     285             : /** \brief Retrieve a vector to all the collection entries.
     286             :  *
     287             :  * This function gathers the entries of all the children collections
     288             :  * and add them to a vector that it then returns.
     289             :  *
     290             :  * The CollectionCollection itself has no entries.
     291             :  *
     292             :  * It is possible to define a CollectionCollection as a child of
     293             :  * another CollectionCollection. The process repeats infinitum
     294             :  * as required.
     295             :  *
     296             :  * \return A copy of all the entries found in the child Collections.
     297             :  */
     298          36 : FileEntry::vector_t CollectionCollection::entries() const
     299             : {
     300          36 :     mustBeValid();
     301             : 
     302          28 :     FileEntry::vector_t all_entries;
     303          68 :     for(auto it = m_collections.begin(); it != m_collections.end(); ++it)
     304             :     {
     305          40 :         all_entries += (*it)->entries();
     306             :     }
     307             : 
     308          28 :     return all_entries;
     309           0 : }
     310             : 
     311             : 
     312             : /** \brief Get an entry from the collection.
     313             :  *
     314             :  * This function returns a shared pointer to a FileEntry object for
     315             :  * the entry with the specified name. To ignore the path part of the
     316             :  * filename while searching for a match, specify
     317             :  * FileCollection::MatchPath::IGNORE as the second argument.
     318             :  * (the default is FileCollection::MatchPath::MATCH.
     319             :  *
     320             :  * \warning
     321             :  * In case of the CollectionCollection, the matching goes from child
     322             :  * collection to child collection in the order they were added to
     323             :  * the CollectionCollection. The first match is returned and at this
     324             :  * point there is nothing linking a FileEntry to its collection so
     325             :  * you will NOT be able to retrieve an istream to access that
     326             :  * FileEntry data. To do that, you must directly call the
     327             :  * getInputStream() function. We may fix that problem at a later
     328             :  * time and offer the getInputStream directly on the FileEntry
     329             :  * instead of the collection. This is problematic at this point
     330             :  * since, as we can see in the zipfile.cpp, we need to have
     331             :  * access to the m_zs offset.
     332             :  *
     333             :  * \note
     334             :  * The collection must be valid or the function raises an exception.
     335             :  *
     336             :  * \param[in] name  A string containing the name of the entry to get.
     337             :  * \param[in] matchpath  Specify MatchPath::MATCH, if the path should match
     338             :  *                       as well, specify MatchPath::IGNORE, if the path
     339             :  *                       should be ignored.
     340             :  *
     341             :  * \return A shared pointer to the found entry. The returned pointer
     342             :  *         is null if no entry is found.
     343             :  *
     344             :  * \sa mustBeValid()
     345             :  */
     346         723 : FileEntry::pointer_t CollectionCollection::getEntry(std::string const & name, MatchPath matchpath) const
     347             : {
     348         723 :     mustBeValid();
     349             : 
     350             :     // Returns the first matching entry.
     351         707 :     FileCollection::pointer_t file_collection;
     352         707 :     FileEntry::pointer_t cep;
     353             : 
     354         707 :     matchEntry(m_collections, name, cep, file_collection, matchpath);
     355             : 
     356        1414 :     return cep;
     357         707 : }
     358             : 
     359             : 
     360             : /** \brief Retrieve pointer to an istream.
     361             :  *
     362             :  * This function returns a shared pointer to an istream defined from the
     363             :  * named entry, which is expected to be available in this collection.
     364             :  *
     365             :  * The function returns a NULL pointer if there is no entry with the
     366             :  * specified name in this CollectionCollection. Note that the name is
     367             :  * searched in all the child collections of the CollectionCollection.
     368             :  *
     369             :  * Note that the function returns a smart pointer to an istream. In
     370             :  * general the CollectionCollection will not hold a copy of that pointer
     371             :  * meaning that if you call getInputStream() multiple times with the same
     372             :  * \p entry_name parameter, you get distinct istream instances each
     373             :  * time.
     374             :  *
     375             :  * By default the \p entry_name parameter is expected to match the full
     376             :  * path and filename (MatchPath::MATCH). If you are looking for a file
     377             :  * and want to ignore the directory name, set the matchpath parameter
     378             :  * to MatchPath::IGNORE.
     379             :  *
     380             :  * \param[in] entry_name  The name of the file to search in the collection.
     381             :  * \param[in] matchpath  Whether the full path or just the filename is matched.
     382             :  *
     383             :  * \return A shared pointer to an open istream for the specified entry.
     384             :  *
     385             :  * \sa FileCollection
     386             :  * \sa DirectoryCollection
     387             :  * \sa ZipFile
     388             :  */
     389         322 : CollectionCollection::stream_pointer_t CollectionCollection::getInputStream(std::string const & entry_name, MatchPath matchpath)
     390             : {
     391         322 :     mustBeValid();
     392             : 
     393         306 :     FileCollection::pointer_t file_collection;
     394         306 :     FileEntry::pointer_t cep;
     395             : 
     396         306 :     matchEntry(m_collections, entry_name, cep, file_collection, matchpath);
     397             : 
     398         612 :     return cep ? file_collection->getInputStream(entry_name) : nullptr;
     399         306 : }
     400             : 
     401             : 
     402             : /** \brief Return the size of the of this collection.
     403             :  *
     404             :  * This function computes the total size of this collection which
     405             :  * is to sum of the size of its child collections.
     406             :  *
     407             :  * \warning
     408             :  * This function has the side effect of loading all the data from
     409             :  * DirectoryCollection objects.
     410             :  *
     411             :  * \return The total size of the collection.
     412             :  */
     413          63 : size_t CollectionCollection::size() const
     414             : {
     415          63 :     mustBeValid();
     416             : 
     417          55 :     size_t sz(0);
     418         158 :     for(auto it = m_collections.begin(); it != m_collections.end(); ++it)
     419             :     {
     420         103 :         sz += (*it)->size();
     421             :     }
     422             : 
     423          55 :     return sz;
     424             : }
     425             : 
     426             : 
     427             : /** \brief Check whether the collection is valid.
     428             :  *
     429             :  * This function verifies that the collection is valid. If not, an
     430             :  * exception is raised. Many other functions from the various collection
     431             :  * functions are calling this function before accessing data.
     432             :  *
     433             :  * \exception InvalidStateException
     434             :  * This exception is raised if the m_valid field is currently false and
     435             :  * thus most of the collection data is considered invalid.
     436             :  */
     437        1581 : void CollectionCollection::mustBeValid() const
     438             : {
     439             :     // self must be valid
     440        1581 :     FileCollection::mustBeValid();
     441             : 
     442        5009 :     for(auto it = m_collections.begin(); it != m_collections.end(); ++it)
     443             :     {
     444             :         // each collection in the collection must be valid since we
     445             :         // may hit any one of them
     446        3507 :         (*it)->mustBeValid();
     447             :     }
     448        1502 : }
     449             : 
     450             : 
     451             : } // zipios namespace
     452             : 
     453             : // Local Variables:
     454             : // mode: cpp
     455             : // indent-tabs-mode: nil
     456             : // c-basic-offset: 4
     457             : // tab-width: 4
     458             : // End:
     459             : 
     460             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.14

Snap C++ | List of projects | List of versions