LCOV - code coverage report
Current view: top level - src - filecollection.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 91 91 100.0 %
Date: 2019-04-24 14:10:30 Functions: 25 26 96.2 %
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-2019  Made to Order Software Corporation
       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::FileCollection.
      24             :  *
      25             :  * This file defines all the FileCollection functions that are not
      26             :  * pure virtual. The file also includes documentation for all those
      27             :  * functions.
      28             :  */
      29             : 
      30             : #include "zipios/filecollection.hpp"
      31             : 
      32             : #include "zipios/zipiosexceptions.hpp"
      33             : 
      34             : #include <algorithm>
      35             : 
      36             : 
      37             : namespace zipios
      38             : {
      39             : 
      40             : 
      41             : 
      42             : namespace
      43             : {
      44             : 
      45             : /** \brief A default filename for unnamed collections.
      46             :  *
      47             :  * This string represents the default m_filename value when a collection
      48             :  * is created without a filename.
      49             :  */
      50             : char const *g_default_filename = "-";
      51             : 
      52             : 
      53             : /** \brief Class object used with the std::find_if() function.
      54             :  *
      55             :  * This function object is used with the STL find_if algorithm to
      56             :  * find a FileEntry in a container, which name (as obtained with
      57             :  * FileEntry::getName()) is identical to the name specified in the
      58             :  * MatchName constructor.
      59             :  */
      60     2457810 : class MatchName
      61             : {
      62             : public:
      63             :     /** \brief Initialize a MatchName object.
      64             :      *
      65             :      * This function saves the name to search in the FileCollection.
      66             :      *
      67             :      * This class expect the name to be a full path and file name
      68             :      * with extension. The full name has to match.
      69             :      *
      70             :      * \param[in] name  The name of the file being searched.
      71             :      */
      72      273090 :     explicit MatchName(std::string const& name)
      73      273090 :         : m_name(name)
      74             :     {
      75      273090 :     }
      76             : 
      77             :     /** \brief Compare an entry to this MatchName.
      78             :      *
      79             :      * This function compares the full name of the entry with the
      80             :      * saved full name. If equal, then it returns true. It is used
      81             :      * with the std::find_if() function.
      82             :      *
      83             :      * \todo
      84             :      * We could transform that with lambda at some point.
      85             :      *
      86             :      * \param[in] entry  The entry to compare with the MatchName.
      87             :      *
      88             :      * \return true if the name of the entry matches the MatchName.
      89             :      */
      90   104164814 :     bool operator() (FileEntry::pointer_t entry) const
      91             :     {
      92   104164814 :         return entry->getName() == m_name;
      93             :     }
      94             : 
      95             : private:
      96             :     std::string const       m_name;
      97             : };
      98             : 
      99             : 
     100             : /** \brief Class object used with the std::find_if() function.
     101             :  *
     102             :  * This function object is used with the STL find_if algorithm to
     103             :  * find a FileEntry in a container, which name (as obtained with
     104             :  * FileEntry::getFileName()) is identical to the name specified in the
     105             :  * MatchFileName constructor.
     106             :  *
     107             :  * \warning
     108             :  * The file name cannot include a '/' in this case or the search will
     109             :  * always fail.
     110             :  */
     111       70848 : class MatchFileName
     112             : {
     113             : public:
     114             :     /** \brief Initialize a MatchFileName object.
     115             :      *
     116             :      * This function saves the base name to search in the
     117             :      * FileCollection.
     118             :      *
     119             :      * This class expect the name to be a base file name, eventually with
     120             :      * an extension. If the name includes a slash then the search will
     121             :      * always fail.
     122             :      *
     123             :      * \param[in] name  The name of the file being searched.
     124             :      */
     125        7872 :     explicit MatchFileName(std::string const& name)
     126        7872 :         : m_name(name)
     127             :     {
     128        7872 :     }
     129             : 
     130             :     /** \brief Compare an entry to this MatchFileName.
     131             :      *
     132             :      * This function compares the base name of the entry with the
     133             :      * saved base name. If equal, then it returns true. It is used
     134             :      * with the std::find_if() function.
     135             :      *
     136             :      * \todo
     137             :      * We could transform that with lambda at some point.
     138             :      *
     139             :      * \param[in] entry  The entry to compare with the MatchFileName.
     140             :      *
     141             :      * \return true if the name of the entry matches the MatchFileName.
     142             :      */
     143     3465480 :     bool operator() (FileEntry::pointer_t entry) const
     144             :     {
     145     3465480 :         return entry->getFileName() == m_name;
     146             :     }
     147             : 
     148             : private:
     149             :     std::string const       m_name;
     150             : };
     151             : 
     152             : 
     153             : } // no name namespace
     154             : 
     155             : 
     156             : 
     157             : /** \class FileCollection
     158             :  * \brief Base class for various file collections.
     159             :  *
     160             :  * FileCollection is an abstract baseclass that represents a
     161             :  * collection of files. The specializations of FileCollection
     162             :  * represents different origins of file collections, such as
     163             :  * directories, simple filename lists and compressed archives.
     164             :  */
     165             : 
     166             : 
     167             : /** \typedef std::shared_ptr<std::istream> FileCollection::stream_pointer_t;
     168             :  * \brief A shared pointer to an input stream.
     169             :  *
     170             :  * This type of pointer is used whenever you retrieve an input stream
     171             :  * from a file collection such as the ZipFile class. Having shared
     172             :  * pointers ensures that the pointers can be shared between various
     173             :  * functions and it gets deleted in the end.
     174             :  */
     175             : 
     176             : 
     177             : /** \fn stream_pointer_t FileCollection::getInputStream(std::string const& entry_name, MatchPath matchpath = MatchPath::MATCH);
     178             :  * \brief Retrieve pointer to an istream.
     179             :  *
     180             :  * This function returns a shared pointer to an istream defined from the
     181             :  * named entry which is expected to be available in this collection.
     182             :  *
     183             :  * The function returns a NULL pointer if there is no entry with the
     184             :  * specified name in this FileCollection.
     185             :  *
     186             :  * Note that the function returns a smart pointer to an istream. In
     187             :  * general the FileCollection will not hold that pointer meaning that
     188             :  * if you call getInputStream() multiple times with the same
     189             :  * \p entry_name parameter, you get distinct istream instances each
     190             :  * time.
     191             :  *
     192             :  * By default the \p entry_name parameter is expected to match the full
     193             :  * path and filename (MatchPath::MATCH). If you are looking for a file
     194             :  * and want to ignore the directory name, set the matchpath parameter
     195             :  * to MatchPath::IGNORE.
     196             :  *
     197             :  * \warning
     198             :  * In version 1.0 there was a version of the function accepting a
     199             :  * FileEntry instead of a filename. That function was simply calling
     200             :  * this function with file_entry->getName() and MatchPath::MATCH so
     201             :  * you can convert the call with:
     202             :  *
     203             :  * \code
     204             :  *      // old code:
     205             :  *      ConstEntryPointer ent = zf.getEntry("file2.txt", FileCollection::IGNORE);
     206             :  *      if(ent)
     207             :  *      {
     208             :  *          auto_ptr<istream> is(getInputStream(ent));
     209             :  *          if(is)
     210             :  *          {
     211             :  *              // got access to the file in the archive
     212             :  *              ...
     213             :  *          }
     214             :  *      }
     215             :  *
     216             :  *      // new code:
     217             :  *      zipios::FileEntry::pointer_t ent(zf.getEntry(argv[2], zipios::FileCollection::MatchPath::IGNORE));
     218             :  *      if(ent)
     219             :  *      {
     220             :  *          zipios::ZipFile::stream_pointer_t is(zf.getInputStream(ent->getName()));
     221             :  *          if(is)
     222             :  *          {
     223             :  *              // got access to the file in the archive
     224             :  *              ...
     225             :  *          }
     226             :  *      }
     227             :  * \endcode
     228             :  *
     229             :  * \par
     230             :  * There are two reasons for the change: (1) the function really just called
     231             :  * the other with getName() and thus there was no reason to have two
     232             :  * functions; and (2) the function did NOT test whether the entry was one
     233             :  * that this collection owned making it feel like you could call the
     234             :  * getInputStream() function of collection A with entry of collection B
     235             :  * and still get a valid stream.
     236             :  *
     237             :  * \param[in] entry_name  The name of the file to search in the collection.
     238             :  * \param[in] matchpath  Whether the full path or just the filename is matched.
     239             :  *
     240             :  * \return A shared pointer to an open istream for the specified entry.
     241             :  *
     242             :  * \sa CollectionCollection
     243             :  * \sa DirectoryCollection
     244             :  * \sa ZipFile
     245             :  */
     246             : 
     247             : 
     248             : /** \fn FileCollection::pointer_t FileCollection::clone() const;
     249             :  * \brief Create a clone of this object.
     250             :  *
     251             :  * This function creates a heap allocated clone of the object this
     252             :  * method is called for.
     253             :  *
     254             :  * \return A shared pointer to a copy of the object this method is called for.
     255             :  */
     256             : 
     257             : 
     258             : /** \brief Initializes a FileCollection object.
     259             :  *
     260             :  * This FileCollection constructor initializes the object and
     261             :  * mark it as invalid. In most cases an invalid collection cannot
     262             :  * be used for anything. You may make it valid by copying a valid
     263             :  * collection in it.
     264             :  *
     265             :  * By default the FileCollection is given the special filename "-".
     266             :  *
     267             :  * The collection is empty and marked as invalid.
     268             :  */
     269         569 : FileCollection::FileCollection(std::string const& filename)
     270         569 :     : m_filename(filename.empty() ? g_default_filename : filename)
     271             :     //, m_entries() -- auto-init
     272             :     //, m_valid(true) -- auto-init
     273             : {
     274         569 : }
     275             : 
     276             : 
     277             : /** \brief Copy a FileCollection in a new one.
     278             :  *
     279             :  * This constructor copies a file collection (\p src) in a new collection.
     280             :  *
     281             :  * The copy entries that all the entries from the source collection get
     282             :  * cloned in the copy. This means entries in the source or new collection
     283             :  * can be modified and it has no effect on the entries in the other
     284             :  * collection.
     285             :  *
     286             :  * \param[in] src  The source collection to copy in this collection.
     287             :  */
     288         101 : FileCollection::FileCollection(FileCollection const& src)
     289             :     : m_filename(src.m_filename)
     290             :     //, m_entries() -- see below
     291         101 :     , m_valid(src.m_valid)
     292             : {
     293         101 :     m_entries.reserve(src.m_entries.size());
     294       14430 :     for(auto it = src.m_entries.begin(); it != src.m_entries.end(); ++it)
     295             :     {
     296       14329 :         m_entries.push_back((*it)->clone());
     297             :     }
     298         101 : }
     299             : 
     300             : 
     301             : /** \brief Replace the content of a collection with a copy of another collection.
     302             :  *
     303             :  * This function copies the \p rhs collection in this collection.
     304             :  *
     305             :  * Note that the entries in the this collection get released. If you still
     306             :  * have a reference to them in a shared pointer, they will not be deleted.
     307             :  *
     308             :  * The entries in \p rhs get cloned so modifying the entries in the source
     309             :  * or the destination has no effect on the entries of the other collection.
     310             :  *
     311             :  * \param[in] rhs  The source FileCollection to copy.
     312             :  *
     313             :  * \return A reference to this FileCollection object.
     314             :  */
     315          21 : FileCollection& FileCollection::operator = (FileCollection const& rhs)
     316             : {
     317          21 :     if(this != &rhs)
     318             :     {
     319          21 :         m_filename = rhs.m_filename;
     320             : 
     321          21 :         m_entries.clear();
     322          21 :         m_entries.reserve(rhs.m_entries.size());
     323        6449 :         for(auto it(rhs.m_entries.begin()); it != rhs.m_entries.end(); ++it)
     324             :         {
     325        6428 :             m_entries.push_back((*it)->clone());
     326             :         }
     327             : 
     328          21 :         m_valid = rhs.m_valid;
     329             :     }
     330             : 
     331          21 :     return *this;
     332             : }
     333             : 
     334             : 
     335             : /** \brief Make sure the resources are released.
     336             :  *
     337             :  * The FileCollection destructor makes sure that any resources
     338             :  * still allocated get released.
     339             :  *
     340             :  * For example, the ZipFile implementation calls the close()
     341             :  * function.
     342             :  *
     343             :  * \note
     344             :  * Note that the entries generally get released when this
     345             :  * destructor is called. However, since we are using shared
     346             :  * pointers, you may still hold valid pointers to the entries
     347             :  * even after the FileCollection destructor was called.
     348             :  */
     349         670 : FileCollection::~FileCollection()
     350             : {
     351         670 : }
     352             : 
     353             : 
     354             : /** \brief Add an entry to this collection.
     355             :  *
     356             :  * This function adds an entry to the file collection allowing you to
     357             :  * create a FileCollection from the exact files you want to have in
     358             :  * the collection instead of having to read an entire directory as
     359             :  * the DirectoryCollection offers by default.
     360             :  *
     361             :  * \warning
     362             :  * This function creates a clone of the entry to make sure that
     363             :  * the caller's entry can be modified without affecting the
     364             :  * FileCollection.
     365             :  *
     366             :  * \param[in] entry  The entry to add to the FileCollection.
     367             :  */
     368       65677 : void FileCollection::addEntry(FileEntry const & entry)
     369             : {
     370       65677 :     m_entries.push_back(entry.clone());
     371       65677 : }
     372             : 
     373             : 
     374             : /** \brief Close the current FileEntry of this FileCollection.
     375             :  *
     376             :  * This function closes the current file entry.
     377             :  */
     378         660 : void FileCollection::close()
     379             : {
     380         660 :     m_entries.clear();
     381         660 :     m_filename = g_default_filename;
     382         660 :     m_valid = false;
     383         660 : }
     384             : 
     385             : 
     386             : /** \brief Retrieve the array of entries.
     387             :  *
     388             :  * This function returns a copy of the file collection vector of entries.
     389             :  * Note that the vector is copied but not the entries, so modifications
     390             :  * to the entries will be reflected in this FileCollection entries.
     391             :  * However, adding and removing entries to the collection is not
     392             :  * reflected in the copy.
     393             :  *
     394             :  * \return A vector containing the entries of this FileCollection.
     395             :  */
     396      282494 : FileEntry::vector_t FileCollection::entries() const
     397             : {
     398      282494 :     mustBeValid();
     399             : 
     400      282494 :     return m_entries;
     401             : }
     402             : 
     403             : 
     404             : /** \brief Get an entry from this collection.
     405             :  *
     406             :  * This function returns a shared pointer to a FileEntry object for
     407             :  * the entry with the specified name. To ignore the path part of the
     408             :  * filename while searching for a match, specify FileCollection::IGNORE
     409             :  * as the second argument.
     410             :  *
     411             :  * \note
     412             :  * The collection must be valid or the function raises an exception.
     413             :  *
     414             :  * \param[in] name  A string containing the name of the entry to get.
     415             :  * \param[in] matchpath  Speficy MatchPath::MATCH, if the path should match
     416             :  *                       as well, specify MatchPath::IGNORE, if the path
     417             :  *                       should be ignored.
     418             :  *
     419             :  * \return A shared pointer to the found entry. The returned pointer
     420             :  *         is null if no entry is found.
     421             :  *
     422             :  * \sa mustBeValid()
     423             :  */
     424      280962 : FileEntry::pointer_t FileCollection::getEntry(std::string const& name, MatchPath matchpath) const
     425             : {
     426             :     // make sure the entries were loaded if necessary
     427      280962 :     entries();
     428             : 
     429      280962 :     mustBeValid();
     430             : 
     431      280962 :     FileEntry::vector_t::const_iterator iter;
     432      280962 :     if(matchpath == MatchPath::MATCH)
     433             :     {
     434      273090 :         iter = std::find_if(m_entries.begin(), m_entries.end(), MatchName(name));
     435             :     }
     436             :     else
     437             :     {
     438        7872 :         iter = std::find_if(m_entries.begin(), m_entries.end(), MatchFileName(name));
     439             :     }
     440             : 
     441      280962 :     return iter == m_entries.end() ? FileEntry::pointer_t() : *iter;
     442             : }
     443             : 
     444             : 
     445             : /** \brief Returns the name of the FileCollection.
     446             :  *
     447             :  * This function returns the filename of the collection as a whole.
     448             :  *
     449             :  * \note
     450             :  * The collection my be valid.
     451             :  *
     452             :  * \return The name of the FileCollection.
     453             :  *
     454             :  * \sa mustBeValid()
     455             :  */
     456         355 : std::string FileCollection::getName() const
     457             : {
     458         355 :     mustBeValid();
     459         329 :     return m_filename;
     460             : }
     461             : 
     462             : 
     463             : /** \brief Returns the number of entries in the FileCollection.
     464             :  *
     465             :  * This function returns the number of entries in the collection.
     466             :  *
     467             :  * \note
     468             :  * The collection my be valid.
     469             :  *
     470             :  * \return The number of entries in the FileCollection.
     471             :  *
     472             :  * \sa mustBeValid()
     473             :  */
     474         462 : size_t FileCollection::size() const
     475             : {
     476             :     // make sure the entries were loaded if necessary
     477         462 :     entries();
     478             : 
     479         443 :     mustBeValid();
     480         443 :     return m_entries.size();
     481             : }
     482             : 
     483             : 
     484             : /** \brief Check whether the current collection is valid.
     485             :  *
     486             :  * This function returns true if the collection is valid.
     487             :  *
     488             :  * Note that by default (just after a new) a collection is
     489             :  * not considered valid.
     490             :  *
     491             :  * \return true if the collection is valid.
     492             :  */
     493         374 : bool FileCollection::isValid() const
     494             : {
     495         374 :     return m_valid;
     496             : }
     497             : 
     498             : 
     499             : /** \brief Check whether the collection is valid.
     500             :  *
     501             :  * This function verifies that the collection is valid. If not, an
     502             :  * exception is raised. Many other functions from the various collection
     503             :  * functions are calling this function before accessing data.
     504             :  *
     505             :  * \exception InvalidStateException
     506             :  * This exception is raised if the m_valid field is currently false and
     507             :  * thus most of the collection data is considered invalid.
     508             :  */
     509     1034228 : void FileCollection::mustBeValid() const
     510             : {
     511     1034228 :     if(!m_valid)
     512             :     {
     513         223 :         throw InvalidStateException("Attempted to access an invalid FileCollection");
     514             :     }
     515     1034005 : }
     516             : 
     517             : 
     518             : /** \brief Change the storage method to the specified value.
     519             :  *
     520             :  * This function changes the storage method of all the entries in
     521             :  * this collection to the specified value.
     522             :  *
     523             :  * The size limit is used to know which storage method to use:
     524             :  * small_storage_method for any file that has a size smaller or
     525             :  * equal to the specified limit and large_storage_method for the
     526             :  * others.
     527             :  *
     528             :  * \param[in] limit  The threshold to use to define the compression level.
     529             :  * \param[in] small_storage_method  The storage method for smaller files.
     530             :  * \param[in] large_storage_method  The storage method for larger files.
     531             :  */
     532         105 : void FileCollection::setMethod(size_t limit, StorageMethod small_storage_method, StorageMethod large_storage_method)
     533             : {
     534             :     // make sure the entries were loaded if necessary
     535         105 :     entries();
     536             : 
     537         105 :     mustBeValid();
     538             : 
     539      105757 :     for(auto it(m_entries.begin()); it != m_entries.end(); ++it)
     540             :     {
     541      105652 :         if((*it)->getSize() > limit)
     542             :         {
     543       94634 :             (*it)->setMethod(large_storage_method);
     544             :         }
     545             :         else
     546             :         {
     547       11018 :             (*it)->setMethod(small_storage_method);
     548             :         }
     549             :     }
     550         105 : }
     551             : 
     552             : 
     553             : /** \brief Change the compression level to the specified value.
     554             :  *
     555             :  * This function changes the compression level of all the entries in
     556             :  * this collection to the specified value.
     557             :  *
     558             :  * The size limit is used to know which compression level to use:
     559             :  * small_compression_level for any file that has a size smaller or
     560             :  * equal to the specified limit and large_compression_level for the
     561             :  * others.
     562             :  *
     563             :  * \param[in] limit  The threshold to use to define the compression level.
     564             :  * \param[in] small_compression_level  The compression level for smaller files.
     565             :  * \param[in] large_compression_level  The compression level for larger files.
     566             :  */
     567         105 : void FileCollection::setLevel(size_t limit, FileEntry::CompressionLevel small_compression_level, FileEntry::CompressionLevel large_compression_level)
     568             : {
     569             :     // make sure the entries were loaded if necessary
     570         105 :     entries();
     571             : 
     572         105 :     mustBeValid();
     573             : 
     574      105757 :     for(auto it(m_entries.begin()); it != m_entries.end(); ++it)
     575             :     {
     576      105652 :         if((*it)->getSize() > limit)
     577             :         {
     578       94634 :             (*it)->setLevel(large_compression_level);
     579             :         }
     580             :         else
     581             :         {
     582       11018 :             (*it)->setLevel(small_compression_level);
     583             :         }
     584             :     }
     585         105 : }
     586             : 
     587             : 
     588             : /** \brief Write a FileCollection to the output stream.
     589             :  *
     590             :  * This function writes a simple textual representation of this
     591             :  * FileCollection to the output stream.
     592             :  *
     593             :  * \param[in,out] os  The output stream.
     594             :  * \param[in] collection  The collection to print out.
     595             :  *
     596             :  * \return A reference to the \p os output stream.
     597             :  */
     598           6 : std::ostream& operator << (std::ostream& os, FileCollection const& collection)
     599             : {
     600           6 :     os << "collection '" << collection.getName() << "' {";
     601          12 :     FileEntry::vector_t entries(collection.entries());
     602           6 :     char const *sep("");
     603        5866 :     for(auto it = entries.begin(); it != entries.end(); ++it)
     604             :     {
     605        5860 :         os << sep;
     606        5860 :         sep = ", ";
     607        5860 :         os << (*it)->getName();
     608             :     }
     609           6 :     os << "}";
     610          12 :     return os;
     611             : }
     612             : 
     613             : 
     614           3 : } // zipios namespace
     615             : 
     616             : // Local Variables:
     617             : // mode: cpp
     618             : // indent-tabs-mode: nil
     619             : // c-basic-offset: 4
     620             : // tab-width: 4
     621             : // End:
     622             : 
     623             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.12