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 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 1401 : VirtualSeeker::VirtualSeeker(offset_t start_offset, offset_t end_offset)
93 : : m_start_offset(start_offset)
94 1401 : , m_end_offset(end_offset)
95 : {
96 1401 : if(m_start_offset < 0
97 895 : || m_end_offset < 0)
98 : {
99 765 : throw InvalidException("VirtualSeeker::VirtualSeeker(): the start and end offsets cannot be negative.");
100 : }
101 636 : }
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 97275 : offset_t VirtualSeeker::startOffset() const
150 : {
151 97275 : 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 161717 : void VirtualSeeker::vseekg(std::istream &is, offset_t offset, std::ios::seekdir sd) const
179 : {
180 161717 : switch(sd)
181 : {
182 : case std::ios::cur:
183 342 : break;
184 :
185 : case std::ios::beg:
186 109815 : offset += m_start_offset;
187 109815 : break;
188 :
189 : 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 872 : offset -= m_end_offset;
195 872 : break;
196 :
197 : default:
198 50688 : throw std::logic_error("VirtualSeekManager::vseekg(): error - unknown seekdir");
199 :
200 : }
201 :
202 111029 : is.seekg(offset, sd);
203 111029 : }
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 2029 : 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 2029 : return is.tellg() - m_start_offset;
228 : }
229 :
230 :
231 3 : } // 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
|