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 file that defines zipios::VirtualSeeker. 24 : * 25 : * The zipios::VirtualSeeker is used to handle offsets of a Zip archive 26 : * defined within a larger file. See the 27 : * zipios::ZipFile::openEmbeddedZipFile() function and the appendzip 28 : * tool for additional information. 29 : * 30 : * \sa appendzip.cpp 31 : * \sa zipios::ZipFile::openEmbeddedZipFile() 32 : */ 33 : 34 : #include "zipios/virtualseeker.hpp" 35 : 36 : #include "zipios/zipiosexceptions.hpp" 37 : 38 : 39 : namespace zipios 40 : { 41 : 42 : 43 : /** \class VirtualSeeker 44 : * \brief A virtual class used to see in a file embedded in another. 45 : * 46 : * The virtual seeker class is a simple definition of an object 47 : * that keeps track of a set of specified (virtual) file pointers 48 : * that mark start and end of a file inside another. 49 : * 50 : * An example of its use (and its reason for existence) is to 51 : * keep track of the file endings of a Zip file embedded in another 52 : * file (see the \ref appendzip_anchor "appendzip tool" and 53 : * the ZipFile::openEmbeddedZipFile() function). 54 : * 55 : * \bug 56 : * The class is not linked to an input stream when created or 57 : * the offsets get modified. This means the seek and tell functions 58 : * cannot be sure that the offsets are valid of the specified 59 : * input buffer. 60 : */ 61 : 62 : 63 : /** \brief Create a virtual seeker. 64 : * 65 : * This constructor defines a virtual seeker start and end offsets 66 : * on initialization. By default it is initialized to a transparent 67 : * seeker since the start and end are set to zero. 68 : * 69 : * \note 70 : * If the offsets are left undefined (both set to zero) then the virtual 71 : * seeker is viewed as a transparent seeker, meaning that it seeks in 72 : * the input streams as if it did not exist. 73 : * 74 : * \warning 75 : * The virtual seek end offset is quite peculiar in that it is defined 76 : * as a POSITIVE number from the end of the file, going backward. The 77 : * normal seekg() command expects a negative number of an offset to be 78 : * applied from the end of the file. 79 : * 80 : * \warning 81 : * The class is not attached to one specific input stream so there is no 82 : * way to verify that the offsets are valid (i.e. not representing an 83 : * empty virtual file or having offsets completely outside of the available 84 : * range.) 85 : * 86 : * \exception InvalidException 87 : * The two offsets must be positive. 88 : * 89 : * \param[in] start_offset The start offset of the embedded file. 90 : * \param[in] end_offset The end offset of the embedded file. 91 : */ 92 1416 : VirtualSeeker::VirtualSeeker(offset_t start_offset, offset_t end_offset) 93 1416 : : m_start_offset(start_offset) 94 1416 : , m_end_offset(end_offset) 95 : { 96 1416 : if(m_start_offset < 0 97 904 : || m_end_offset < 0) 98 : { 99 768 : throw InvalidException("VirtualSeeker::VirtualSeeker(): the start and end offsets cannot be negative."); 100 : } 101 648 : } 102 : 103 : 104 : /** \brief Set the offsets of the virtual seeker. 105 : * 106 : * This function can be used to change the virtual seeker offsets. 107 : * 108 : * \exception InvalidException 109 : * The start offset must be before or equal to the end offset or 110 : * this exception is raised. 111 : * 112 : * \param[in] start_offset The new start offset. 113 : * \param[in] end_offset The new end offset. 114 : */ 115 1024 : void VirtualSeeker::setOffsets(offset_t start_offset, offset_t end_offset) 116 : { 117 1024 : if(start_offset < 0 118 512 : || end_offset < 0) 119 : { 120 768 : throw InvalidException("VirtualSeeker::VirtualSeeker(): the start and end offsets cannot be negative."); 121 : } 122 : 123 256 : m_start_offset = start_offset; 124 256 : m_end_offset = end_offset; 125 256 : } 126 : 127 : 128 : /** \brief Retrieve the current offsets. 129 : * 130 : * This function retrieves the start and end offsets from the virtual 131 : * seeker object. 132 : * 133 : * \param[out] start_offset Returns the start offset. 134 : * \param[out] end_offset Returns the end offset. 135 : */ 136 512 : void VirtualSeeker::getOffsets(offset_t & start_offset, offset_t & end_offset) const 137 : { 138 512 : start_offset = m_start_offset; 139 512 : end_offset = m_end_offset; 140 512 : } 141 : 142 : 143 : /** \brief Return the start offset. 144 : * 145 : * This function returns a copy of the start offset. 146 : * 147 : * \return The start offset. 148 : */ 149 53573 : offset_t VirtualSeeker::startOffset() const 150 : { 151 53573 : return m_start_offset; 152 : } 153 : 154 : 155 : /** \brief Return the end offset. 156 : * 157 : * This function returns a copy of the end offset. 158 : * 159 : * \return The end offset. 160 : */ 161 512 : offset_t VirtualSeeker::endOffset() const 162 : { 163 512 : return m_end_offset; 164 : } 165 : 166 : 167 : /** \brief Seek within the embedded file. 168 : * 169 : * This function changes the file pointer in \p is to the position 170 : * specified in offset. 171 : * 172 : * The direction can be indicated by \p sd. 173 : * 174 : * \param[in,out] is The stream which pointer is to be changed. 175 : * \param[in] offset Relative position to set the input pointer to. 176 : * \param[in] sd The stream direction to use to apply offset. 177 : */ 178 112322 : void VirtualSeeker::vseekg(std::istream &is, offset_t offset, std::ios::seekdir sd) const 179 : { 180 112322 : switch(sd) 181 : { 182 325 : case std::ios::cur: 183 325 : break; 184 : 185 60425 : case std::ios::beg: 186 60425 : offset += m_start_offset; 187 60425 : break; 188 : 189 884 : case std::ios::end: 190 : // This definitively looks weird because this class makes use 191 : // of a POSITIVE offset from the end of the file as the end 192 : // offset. The parameter 'offset' is expected to be negative 193 : // or zero in this case. 194 884 : offset -= m_end_offset; 195 884 : break; 196 : 197 50688 : default: 198 50688 : throw std::logic_error("VirtualSeekManager::vseekg(): error - unknown seekdir"); 199 : 200 : } 201 : 202 61634 : is.seekg(offset, sd); 203 61634 : } 204 : 205 : 206 : /** \brief Current position within the sub-file. 207 : * 208 : * This function calculates the position (file current pointer) within 209 : * the embedded file in the specified stream. 210 : * 211 : * If the position in the existing file is too large or too small, then 212 : * the function returns -1. 213 : * 214 : * \param[in] is The stream to get the position from. 215 : * 216 : * \return The stream offset within the embedded file. 217 : */ 218 2036 : std::streampos VirtualSeeker::vtellg(std::istream & is) const 219 : { 220 : /** \TODO 221 : * We may want to get the size of the file and verify that the 222 : * resulting position is valid. The m_end_offset does not really 223 : * mean anything at this point that we could use to verify the 224 : * position boundaries (since it is a positive size from the 225 : * end of the file.) 226 : */ 227 4072 : return is.tellg() - m_start_offset; 228 : } 229 : 230 : 231 : } // zipios namespace 232 : 233 : // Local Variables: 234 : // mode: cpp 235 : // indent-tabs-mode: nil 236 : // c-basic-offset: 4 237 : // tab-width: 4 238 : // End: 239 : 240 : // vim: ts=4 sw=4 et