xrootd
Loading...
Searching...
No Matches
XrdZipCDFH.hh
Go to the documentation of this file.
1//------------------------------------------------------------------------------
2// Copyright (c) 2011-2014 by European Organization for Nuclear Research (CERN)
3// Author: Michal Simon <michal.simon@cern.ch>
4//------------------------------------------------------------------------------
5// This file is part of the XRootD software suite.
6//
7// XRootD is free software: you can redistribute it and/or modify
8// it under the terms of the GNU Lesser General Public License as published by
9// the Free Software Foundation, either version 3 of the License, or
10// (at your option) any later version.
11//
12// XRootD 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
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU Lesser General Public License
18// along with XRootD. If not, see <http://www.gnu.org/licenses/>.
19//
20// In applying this licence, CERN does not waive the privileges and immunities
21// granted to it by virtue of its status as an Intergovernmental Organization
22// or submit itself to any jurisdiction.
23//------------------------------------------------------------------------------
24
25#ifndef SRC_XRDZIP_XRDZIPCDFH_HH_
26#define SRC_XRDZIP_XRDZIPCDFH_HH_
27
28#include "XrdZip/XrdZipLFH.hh"
29#include "XrdZip/XrdZipUtils.hh"
31
32#include <string>
33#include <algorithm>
34#include <iterator>
35#include <unordered_map>
36#include <memory>
37#include <tuple>
38
39#include <sys/types.h>
40
41namespace XrdZip
42{
43 //---------------------------------------------------------------------------
44 // Forward declaration for CDFH
45 //---------------------------------------------------------------------------
46 struct CDFH;
47
48 //---------------------------------------------------------------------------
49 // Vector of Central Directory records
50 //---------------------------------------------------------------------------
51 typedef std::vector<std::unique_ptr<CDFH>> cdvec_t;
52
53 //---------------------------------------------------------------------------
54 // Map file name to index of CD record
55 //---------------------------------------------------------------------------
56 typedef std::unordered_map<std::string, size_t> cdmap_t;
57
58 //---------------------------------------------------------------------------
59 // Map of Central Directory records
60 //---------------------------------------------------------------------------
61 typedef std::unordered_map<std::string, std::unique_ptr<CDFH>> cdrecs_t;
62
63 //---------------------------------------------------------------------------
64 // A data structure representing the Central Directory File header record
65 //---------------------------------------------------------------------------
66 struct CDFH
67 {
68 //-------------------------------------------------------------------------
69 // Parse central directory
70 // @param buffer : buffer containing the CD records
71 // @param bufferSize : size of the buffer
72 // @param nbCdRecords : nb of CD records
73 // @return : vector of CD records / file name to index mapping
74 //-------------------------------------------------------------------------
75 inline static std::tuple<cdvec_t, cdmap_t> Parse( const char *buffer, uint32_t bufferSize, uint16_t nbCdRecords )
76 {
77 uint32_t offset = 0;
78 cdvec_t cdvec;
79 cdmap_t cdmap;
80 cdvec.reserve( nbCdRecords );
81
82 for( size_t i = 0; i < nbCdRecords; ++i )
83 {
84 if( bufferSize < cdfhBaseSize ) break;
85 // check the signature
86 uint32_t signature = to<uint32_t>( buffer + offset );
87 if( signature != cdfhSign ) throw bad_data();
88 // parse the record
89 std::unique_ptr<CDFH> cdfh( new CDFH( buffer + offset, bufferSize ) );
90 offset += cdfh->cdfhSize;
91 bufferSize -= cdfh->cdfhSize;
92 cdmap[cdfh->filename] = i;
93 cdvec.push_back( std::move( cdfh ) );
94 }
95
96 return std::make_tuple( std::move( cdvec ), std::move( cdmap ) );
97 }
98
99 //-------------------------------------------------------------------------
100 // Parse central directory
101 // @param buffer : buffer containing the CD records
102 // @param bufferSize : size of the buffer
103 // @return : vector of CD records / file name to index mapping
104 //-------------------------------------------------------------------------
105 inline static std::tuple<cdvec_t, cdmap_t> Parse( const char *&buffer, uint32_t bufferSize )
106 {
107 cdvec_t cdvec;
108 cdmap_t cdmap;
109 size_t i = 0;
110 while( bufferSize > 0 )
111 {
112 if( bufferSize < sizeof( uint32_t ) ) throw bad_data();
113 // check the signature
114 uint32_t signature = to<uint32_t>( buffer );
115 if( signature != cdfhSign )
116 return std::make_tuple( std::move( cdvec ), std::move( cdmap ) );
117 // parse the record
118 std::unique_ptr<CDFH> cdfh( new CDFH( buffer ) );
119 if( bufferSize < cdfh->cdfhSize ) throw bad_data();
120 buffer += cdfh->cdfhSize;
121 bufferSize -= cdfh->cdfhSize;
122 cdmap[cdfh->filename] = i++;
123 cdvec.push_back( std::move( cdfh ) );
124 }
125
126 return std::make_tuple( std::move( cdvec ), std::move( cdmap ) );
127 }
128
129 //---------------------------------------------------------------------------
130 // Calculate size of the Central Directory
131 //---------------------------------------------------------------------------
132 inline static size_t CalcSize( const cdvec_t &cdvec, uint32_t orgcdsz, uint32_t orgcdcnt )
133 {
134 size_t size = 0;
135 auto itr = cdvec.begin() + orgcdcnt;
136 for( ; itr != cdvec.end() ; ++itr )
137 {
138 CDFH *cdfh = itr->get();
139 size += cdfh->cdfhSize;
140 }
141 return size + orgcdsz;
142 }
143
144 inline static void Serialize( uint32_t orgcdcnt,
145 const buffer_t &orgcdbuf,
146 const cdvec_t &cdvec,
147 buffer_t &buffer )
148 {
149 std::copy( orgcdbuf.begin(), orgcdbuf.end(), std::back_inserter( buffer ) );
150 auto itr = cdvec.begin() + orgcdcnt;
151 for( ; itr != cdvec.end() ; ++itr )
152 {
153 CDFH *cdfh = itr->get();
154 cdfh->Serialize( buffer );
155 }
156 }
157
158 //-------------------------------------------------------------------------
159 // Constructor from Local File Header
160 //-------------------------------------------------------------------------
161 CDFH( LFH *lfh, mode_t mode, uint64_t lfhOffset ):
162 zipVersion( ( 3 << 8 ) | 63 ),
165 timestmp( lfh->timestmp ),
166 ZCRC32( lfh->ZCRC32 ),
170 commentLength( 0 ),
171 nbDisk( 0 ),
172 internAttr( 0 ),
173 externAttr( mode << 16 ),
174 filename( lfh->filename ),
175 extra( new Extra( lfh->extra.get(), lfhOffset ) )
176 {
177 if ( lfhOffset >= ovrflw<uint32_t>::value )
179 else
180 offset = lfhOffset;
181
182 extraLength = extra->totalSize;
183
184 if ( extraLength == 0 )
185 minZipVersion = 10;
186 else
187 minZipVersion = 45;
188
190 }
191
192 //-------------------------------------------------------------------------
193 // Constructor from buffer
194 //-------------------------------------------------------------------------
195 CDFH( const char *buffer, const uint32_t maxSize = 0 )
196 {
197 zipVersion = to<uint16_t>(buffer + 4);
198 minZipVersion = to<uint16_t>(buffer + 6);
199 generalBitFlag = to<uint16_t>(buffer + 8);
200 compressionMethod = to<uint16_t>(buffer + 10);
201 timestmp.time = to<uint16_t>(buffer + 12);
202 timestmp.date = to<uint16_t>(buffer + 14);
203 ZCRC32 = to<uint32_t>(buffer + 16);
204 compressedSize = to<uint32_t>(buffer + 20);
205 uncompressedSize = to<uint32_t>(buffer + 24);
206 filenameLength = to<uint16_t>(buffer + 28);
207 extraLength = to<uint16_t>(buffer + 30);
208 commentLength = to<uint16_t>(buffer + 32);
209 nbDisk = to<uint16_t>(buffer + 34);
210 internAttr = to<uint16_t>(buffer + 36);
211 externAttr = to<uint32_t>(buffer + 38);
212 offset = to<uint32_t>(buffer + 42);
213 if(maxSize > 0 && (uint32_t)(cdfhBaseSize+filenameLength + extraLength + commentLength) > maxSize){
214 throw bad_data();
215 }
216 filename.assign( buffer + 46, filenameLength );
217
218 // now parse the 'extra' (may contain the zip64 extension to CDFH)
219 ParseExtra( buffer + 46 + filenameLength, extraLength );
220
222 }
223
224 //-------------------------------------------------------------------------
225 // Choose the right offset value from the CDFH record
226 //-------------------------------------------------------------------------
227 inline static uint64_t GetOffset( const CDFH &cdfh )
228 {
229 if( cdfh.offset != ovrflw<uint32_t>::value )
230 return cdfh.offset;
231 return cdfh.extra->offset;
232 }
233
234 //-------------------------------------------------------------------------
235 // Parse the extensible data fields
236 //-------------------------------------------------------------------------
237 void ParseExtra( const char *buffer, uint16_t length)
238 {
239 uint8_t ovrflws = Extra::NONE;
240 uint16_t exsize = 0;
241
242 // check if compressed size is overflown
244 {
245 ovrflws |= Extra::CPMSIZE;
246 exsize += sizeof( uint64_t );
247 }
248
249 // check if original size is overflown
251 {
252 ovrflws |= Extra::UCMPSIZE;
253 exsize += sizeof( uint64_t );
254 }
255
256 // check if offset is overflown
258 {
259 ovrflws |= Extra::OFFSET;
260 exsize += sizeof( uint64_t );
261 }
262
263 // check if number of disks is overflown
265 {
266 ovrflws |= Extra::NBDISK;
267 exsize += sizeof( uint32_t );
268 }
269
270 // if the expected size of ZIP64 extension is 0 we
271 // can skip parsing of 'extra'
272 if( exsize == 0 ) return;
273
274 // Parse the extra part
275 buffer = Extra::Find( buffer, length );
276 if( buffer )
277 {
278 extra.reset( new Extra() );
279 extra->FromBuffer( buffer, exsize, ovrflws );
280 }
281 }
282
283 //-------------------------------------------------------------------------
285 //-------------------------------------------------------------------------
286 void Serialize( buffer_t &buffer )
287 {
288 copy_bytes( cdfhSign, buffer );
289 copy_bytes( zipVersion, buffer );
290 copy_bytes( minZipVersion, buffer );
291 copy_bytes( generalBitFlag, buffer );
292 copy_bytes( compressionMethod, buffer );
293 copy_bytes( timestmp.time, buffer );
294 copy_bytes( timestmp.date, buffer );
295 copy_bytes( ZCRC32, buffer );
296 copy_bytes( compressedSize, buffer );
297 copy_bytes( uncompressedSize, buffer );
298 copy_bytes( filenameLength, buffer );
299 copy_bytes( extraLength, buffer );
300 copy_bytes( commentLength, buffer );
301 copy_bytes( nbDisk, buffer );
302 copy_bytes( internAttr, buffer );
303 copy_bytes( externAttr, buffer );
304 copy_bytes( offset, buffer );
305 std::copy( filename.begin(), filename.end(), std::back_inserter( buffer ) );
306 if( extra )
307 extra->Serialize( buffer );
308
309 if ( commentLength > 0 )
310 std::copy( comment.begin(), comment.end(), std::back_inserter( buffer ) );
311 }
312
313 //-------------------------------------------------------------------------
315 //-------------------------------------------------------------------------
316 inline bool IsZIP64() const
317 {
318 return extra.get();
319 }
320
321 //-------------------------------------------------------------------------
323 //-------------------------------------------------------------------------
325 {
327 }
328
329 uint16_t zipVersion; // ZIP version
330 uint16_t minZipVersion; //< minumum ZIP version
331 uint16_t generalBitFlag; //< flags
332 uint16_t compressionMethod; //< compression method
333 dos_timestmp timestmp; //< DOS timestamp
334 uint32_t ZCRC32; //< CRC32
335 uint32_t compressedSize; //< compressed size
336 uint32_t uncompressedSize; //< uncompressed size
337 uint16_t filenameLength; //< filename length
338 uint16_t extraLength; //< size of the ZIP64 extra field
339 uint16_t commentLength; //< comment length
340 uint16_t nbDisk; //< number of disks
341 uint16_t internAttr; //< internal attributes
342 uint32_t externAttr; //< external attributes
343 uint32_t offset; //< offset
344 std::string filename; //< file name
345 std::unique_ptr<Extra> extra; //< ZIP64 extra field
346 std::string comment; //< user comment
347 uint16_t cdfhSize; // size of the record
348
349 //-------------------------------------------------------------------------
350 // the Central Directory File Header signature
351 //-------------------------------------------------------------------------
352 static const uint32_t cdfhSign = 0x02014b50;
353 static const uint16_t cdfhBaseSize = 46;
354 };
355}
356
357#endif /* SRC_XRDZIP_XRDZIPCDFH_HH_ */
Definition XrdZipCDFH.hh:42
std::unordered_map< std::string, std::unique_ptr< CDFH > > cdrecs_t
Definition XrdZipCDFH.hh:61
std::vector< std::unique_ptr< CDFH > > cdvec_t
Definition XrdZipCDFH.hh:51
std::vector< char > buffer_t
Definition XrdZipUtils.hh:56
static void copy_bytes(const INT value, buffer_t &buffer)
Definition XrdZipUtils.hh:62
std::unordered_map< std::string, size_t > cdmap_t
Definition XrdZipCDFH.hh:56
Definition XrdZipCDFH.hh:67
uint32_t uncompressedSize
Definition XrdZipCDFH.hh:336
uint32_t offset
Definition XrdZipCDFH.hh:343
uint16_t cdfhSize
Definition XrdZipCDFH.hh:347
uint16_t nbDisk
Definition XrdZipCDFH.hh:340
static uint64_t GetOffset(const CDFH &cdfh)
Definition XrdZipCDFH.hh:227
std::unique_ptr< Extra > extra
Definition XrdZipCDFH.hh:345
uint16_t internAttr
Definition XrdZipCDFH.hh:341
std::string filename
Definition XrdZipCDFH.hh:344
CDFH(LFH *lfh, mode_t mode, uint64_t lfhOffset)
Definition XrdZipCDFH.hh:161
uint32_t externAttr
Definition XrdZipCDFH.hh:342
static std::tuple< cdvec_t, cdmap_t > Parse(const char *buffer, uint32_t bufferSize, uint16_t nbCdRecords)
Definition XrdZipCDFH.hh:75
uint16_t zipVersion
Definition XrdZipCDFH.hh:329
static const uint16_t cdfhBaseSize
Definition XrdZipCDFH.hh:353
uint16_t extraLength
Definition XrdZipCDFH.hh:338
uint16_t compressionMethod
Definition XrdZipCDFH.hh:332
bool HasDataDescriptor()
Definition XrdZipCDFH.hh:324
static std::tuple< cdvec_t, cdmap_t > Parse(const char *&buffer, uint32_t bufferSize)
Definition XrdZipCDFH.hh:105
uint16_t generalBitFlag
Definition XrdZipCDFH.hh:331
void Serialize(buffer_t &buffer)
Serialize the object into a buffer.
Definition XrdZipCDFH.hh:286
uint32_t ZCRC32
Definition XrdZipCDFH.hh:334
uint16_t commentLength
Definition XrdZipCDFH.hh:339
uint16_t minZipVersion
Definition XrdZipCDFH.hh:330
static size_t CalcSize(const cdvec_t &cdvec, uint32_t orgcdsz, uint32_t orgcdcnt)
Definition XrdZipCDFH.hh:132
static const uint32_t cdfhSign
Definition XrdZipCDFH.hh:352
static void Serialize(uint32_t orgcdcnt, const buffer_t &orgcdbuf, const cdvec_t &cdvec, buffer_t &buffer)
Definition XrdZipCDFH.hh:144
void ParseExtra(const char *buffer, uint16_t length)
Definition XrdZipCDFH.hh:237
uint32_t compressedSize
Definition XrdZipCDFH.hh:335
uint16_t filenameLength
Definition XrdZipCDFH.hh:337
CDFH(const char *buffer, const uint32_t maxSize=0)
Definition XrdZipCDFH.hh:195
bool IsZIP64() const
Definition XrdZipCDFH.hh:316
dos_timestmp timestmp
Definition XrdZipCDFH.hh:333
std::string comment
Definition XrdZipCDFH.hh:346
static const uint16_t flag
Definition XrdZipDataDescriptor.hh:43
Definition XrdZipExtra.hh:39
static const char * Find(const char *buffer, uint16_t length)
Definition XrdZipExtra.hh:101
@ CPMSIZE
Definition XrdZipExtra.hh:164
@ UCMPSIZE
Definition XrdZipExtra.hh:163
@ NONE
Definition XrdZipExtra.hh:162
@ OFFSET
Definition XrdZipExtra.hh:165
@ NBDISK
Definition XrdZipExtra.hh:166
A data structure representing ZIP Local File Header.
Definition XrdZipLFH.hh:42
Definition XrdZipUtils.hh:42
Definition XrdZipUtils.hh:105
uint16_t time
Definition XrdZipUtils.hh:142
uint16_t date
Definition XrdZipUtils.hh:155
Definition XrdZipUtils.hh:49