File indexing completed on 2025-01-18 10:15:38
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #ifndef SRC_XRDZIP_XRDZIPCDFH_HH_
0026 #define SRC_XRDZIP_XRDZIPCDFH_HH_
0027
0028 #include "XrdZip/XrdZipLFH.hh"
0029 #include "XrdZip/XrdZipUtils.hh"
0030 #include "XrdZip/XrdZipDataDescriptor.hh"
0031
0032 #include <string>
0033 #include <algorithm>
0034 #include <iterator>
0035 #include <unordered_map>
0036 #include <memory>
0037 #include <tuple>
0038
0039 #include <sys/types.h>
0040
0041 namespace XrdZip
0042 {
0043
0044
0045
0046 struct CDFH;
0047
0048
0049
0050
0051 typedef std::vector<std::unique_ptr<CDFH>> cdvec_t;
0052
0053
0054
0055
0056 typedef std::unordered_map<std::string, size_t> cdmap_t;
0057
0058
0059
0060
0061 typedef std::unordered_map<std::string, std::unique_ptr<CDFH>> cdrecs_t;
0062
0063
0064
0065
0066 struct CDFH
0067 {
0068
0069
0070
0071
0072
0073
0074
0075 inline static std::tuple<cdvec_t, cdmap_t> Parse( const char *buffer, uint32_t bufferSize, uint16_t nbCdRecords )
0076 {
0077 uint32_t offset = 0;
0078 cdvec_t cdvec;
0079 cdmap_t cdmap;
0080 cdvec.reserve( nbCdRecords );
0081
0082 for( size_t i = 0; i < nbCdRecords; ++i )
0083 {
0084 if( bufferSize < cdfhBaseSize ) break;
0085
0086 uint32_t signature = to<uint32_t>( buffer + offset );
0087 if( signature != cdfhSign ) throw bad_data();
0088
0089 std::unique_ptr<CDFH> cdfh( new CDFH( buffer + offset, bufferSize ) );
0090 offset += cdfh->cdfhSize;
0091 bufferSize -= cdfh->cdfhSize;
0092 cdmap[cdfh->filename] = i;
0093 cdvec.push_back( std::move( cdfh ) );
0094 }
0095
0096 return std::make_tuple( std::move( cdvec ), std::move( cdmap ) );
0097 }
0098
0099
0100
0101
0102
0103
0104
0105 inline static std::tuple<cdvec_t, cdmap_t> Parse( const char *&buffer, uint32_t bufferSize )
0106 {
0107 cdvec_t cdvec;
0108 cdmap_t cdmap;
0109 size_t i = 0;
0110 while( bufferSize > 0 )
0111 {
0112 if( bufferSize < sizeof( uint32_t ) ) throw bad_data();
0113
0114 uint32_t signature = to<uint32_t>( buffer );
0115 if( signature != cdfhSign )
0116 return std::make_tuple( std::move( cdvec ), std::move( cdmap ) );
0117
0118 std::unique_ptr<CDFH> cdfh( new CDFH( buffer ) );
0119 if( bufferSize < cdfh->cdfhSize ) throw bad_data();
0120 buffer += cdfh->cdfhSize;
0121 bufferSize -= cdfh->cdfhSize;
0122 cdmap[cdfh->filename] = i++;
0123 cdvec.push_back( std::move( cdfh ) );
0124 }
0125
0126 return std::make_tuple( std::move( cdvec ), std::move( cdmap ) );
0127 }
0128
0129
0130
0131
0132 inline static size_t CalcSize( const cdvec_t &cdvec, uint32_t orgcdsz, uint32_t orgcdcnt )
0133 {
0134 size_t size = 0;
0135 auto itr = cdvec.begin() + orgcdcnt;
0136 for( ; itr != cdvec.end() ; ++itr )
0137 {
0138 CDFH *cdfh = itr->get();
0139 size += cdfh->cdfhSize;
0140 }
0141 return size + orgcdsz;
0142 }
0143
0144 inline static void Serialize( uint32_t orgcdcnt,
0145 const buffer_t &orgcdbuf,
0146 const cdvec_t &cdvec,
0147 buffer_t &buffer )
0148 {
0149 std::copy( orgcdbuf.begin(), orgcdbuf.end(), std::back_inserter( buffer ) );
0150 auto itr = cdvec.begin() + orgcdcnt;
0151 for( ; itr != cdvec.end() ; ++itr )
0152 {
0153 CDFH *cdfh = itr->get();
0154 cdfh->Serialize( buffer );
0155 }
0156 }
0157
0158
0159
0160
0161 CDFH( LFH *lfh, mode_t mode, uint64_t lfhOffset ):
0162 zipVersion( ( 3 << 8 ) | 63 ),
0163 generalBitFlag( lfh->generalBitFlag ),
0164 compressionMethod( lfh->compressionMethod ),
0165 timestmp( lfh->timestmp ),
0166 ZCRC32( lfh->ZCRC32 ),
0167 compressedSize( lfh->compressedSize ),
0168 uncompressedSize( lfh->uncompressedSize ),
0169 filenameLength( lfh->filenameLength ),
0170 commentLength( 0 ),
0171 nbDisk( 0 ),
0172 internAttr( 0 ),
0173 externAttr( mode << 16 ),
0174 filename( lfh->filename ),
0175 extra( new Extra( lfh->extra.get(), lfhOffset ) )
0176 {
0177 if ( lfhOffset >= ovrflw<uint32_t>::value )
0178 offset = ovrflw<uint32_t>::value;
0179 else
0180 offset = lfhOffset;
0181
0182 extraLength = extra->totalSize;
0183
0184 if ( extraLength == 0 )
0185 minZipVersion = 10;
0186 else
0187 minZipVersion = 45;
0188
0189 cdfhSize = cdfhBaseSize + filenameLength + extraLength + commentLength;
0190 }
0191
0192
0193
0194
0195 CDFH( const char *buffer, const uint32_t maxSize = 0 )
0196 {
0197 zipVersion = to<uint16_t>(buffer + 4);
0198 minZipVersion = to<uint16_t>(buffer + 6);
0199 generalBitFlag = to<uint16_t>(buffer + 8);
0200 compressionMethod = to<uint16_t>(buffer + 10);
0201 timestmp.time = to<uint16_t>(buffer + 12);
0202 timestmp.date = to<uint16_t>(buffer + 14);
0203 ZCRC32 = to<uint32_t>(buffer + 16);
0204 compressedSize = to<uint32_t>(buffer + 20);
0205 uncompressedSize = to<uint32_t>(buffer + 24);
0206 filenameLength = to<uint16_t>(buffer + 28);
0207 extraLength = to<uint16_t>(buffer + 30);
0208 commentLength = to<uint16_t>(buffer + 32);
0209 nbDisk = to<uint16_t>(buffer + 34);
0210 internAttr = to<uint16_t>(buffer + 36);
0211 externAttr = to<uint32_t>(buffer + 38);
0212 offset = to<uint32_t>(buffer + 42);
0213 if(maxSize > 0 && (uint32_t)(cdfhBaseSize+filenameLength + extraLength + commentLength) > maxSize){
0214 throw bad_data();
0215 }
0216 filename.assign( buffer + 46, filenameLength );
0217
0218
0219 ParseExtra( buffer + 46 + filenameLength, extraLength );
0220
0221 cdfhSize = cdfhBaseSize + filenameLength + extraLength + commentLength;
0222 }
0223
0224
0225
0226
0227 inline static uint64_t GetOffset( const CDFH &cdfh )
0228 {
0229 if( cdfh.offset != ovrflw<uint32_t>::value )
0230 return cdfh.offset;
0231 return cdfh.extra->offset;
0232 }
0233
0234
0235
0236
0237 void ParseExtra( const char *buffer, uint16_t length)
0238 {
0239 uint8_t ovrflws = Extra::NONE;
0240 uint16_t exsize = 0;
0241
0242
0243 if( compressedSize == ovrflw<uint32_t>::value)
0244 {
0245 ovrflws |= Extra::CPMSIZE;
0246 exsize += sizeof( uint64_t );
0247 }
0248
0249
0250 if( uncompressedSize == ovrflw<uint32_t>::value )
0251 {
0252 ovrflws |= Extra::UCMPSIZE;
0253 exsize += sizeof( uint64_t );
0254 }
0255
0256
0257 if( offset == ovrflw<uint32_t>::value )
0258 {
0259 ovrflws |= Extra::OFFSET;
0260 exsize += sizeof( uint64_t );
0261 }
0262
0263
0264 if( nbDisk == ovrflw<uint16_t>::value )
0265 {
0266 ovrflws |= Extra::NBDISK;
0267 exsize += sizeof( uint32_t );
0268 }
0269
0270
0271
0272 if( exsize == 0 ) return;
0273
0274
0275 buffer = Extra::Find( buffer, length );
0276 if( buffer )
0277 {
0278 extra.reset( new Extra() );
0279 extra->FromBuffer( buffer, exsize, ovrflws );
0280 }
0281 }
0282
0283
0284
0285
0286 void Serialize( buffer_t &buffer )
0287 {
0288 copy_bytes( cdfhSign, buffer );
0289 copy_bytes( zipVersion, buffer );
0290 copy_bytes( minZipVersion, buffer );
0291 copy_bytes( generalBitFlag, buffer );
0292 copy_bytes( compressionMethod, buffer );
0293 copy_bytes( timestmp.time, buffer );
0294 copy_bytes( timestmp.date, buffer );
0295 copy_bytes( ZCRC32, buffer );
0296 copy_bytes( compressedSize, buffer );
0297 copy_bytes( uncompressedSize, buffer );
0298 copy_bytes( filenameLength, buffer );
0299 copy_bytes( extraLength, buffer );
0300 copy_bytes( commentLength, buffer );
0301 copy_bytes( nbDisk, buffer );
0302 copy_bytes( internAttr, buffer );
0303 copy_bytes( externAttr, buffer );
0304 copy_bytes( offset, buffer );
0305 std::copy( filename.begin(), filename.end(), std::back_inserter( buffer ) );
0306 if( extra )
0307 extra->Serialize( buffer );
0308
0309 if ( commentLength > 0 )
0310 std::copy( comment.begin(), comment.end(), std::back_inserter( buffer ) );
0311 }
0312
0313
0314
0315
0316 inline bool IsZIP64() const
0317 {
0318 return extra.get();
0319 }
0320
0321
0322
0323
0324 bool HasDataDescriptor()
0325 {
0326 return generalBitFlag & DataDescriptor::flag;
0327 }
0328
0329 uint16_t zipVersion;
0330 uint16_t minZipVersion;
0331 uint16_t generalBitFlag;
0332 uint16_t compressionMethod;
0333 dos_timestmp timestmp;
0334 uint32_t ZCRC32;
0335 uint32_t compressedSize;
0336 uint32_t uncompressedSize;
0337 uint16_t filenameLength;
0338 uint16_t extraLength;
0339 uint16_t commentLength;
0340 uint16_t nbDisk;
0341 uint16_t internAttr;
0342 uint32_t externAttr;
0343 uint32_t offset;
0344 std::string filename;
0345 std::unique_ptr<Extra> extra;
0346 std::string comment;
0347 uint16_t cdfhSize;
0348
0349
0350
0351
0352 static const uint32_t cdfhSign = 0x02014b50;
0353 static const uint16_t cdfhBaseSize = 46;
0354 };
0355 }
0356
0357 #endif