Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:15:38

0001 //------------------------------------------------------------------------------
0002 // Copyright (c) 2011-2014 by European Organization for Nuclear Research (CERN)
0003 // Author: Michal Simon <michal.simon@cern.ch>
0004 //------------------------------------------------------------------------------
0005 // This file is part of the XRootD software suite.
0006 //
0007 // XRootD is free software: you can redistribute it and/or modify
0008 // it under the terms of the GNU Lesser General Public License as published by
0009 // the Free Software Foundation, either version 3 of the License, or
0010 // (at your option) any later version.
0011 //
0012 // XRootD is distributed in the hope that it will be useful,
0013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
0014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015 // GNU General Public License for more details.
0016 //
0017 // You should have received a copy of the GNU Lesser General Public License
0018 // along with XRootD.  If not, see <http://www.gnu.org/licenses/>.
0019 //
0020 // In applying this licence, CERN does not waive the privileges and immunities
0021 // granted to it by virtue of its status as an Intergovernmental Organization
0022 // or submit itself to any jurisdiction.
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   // Forward declaration for CDFH
0045   //---------------------------------------------------------------------------
0046   struct CDFH;
0047 
0048   //---------------------------------------------------------------------------
0049   // Vector of Central Directory records
0050   //---------------------------------------------------------------------------
0051   typedef std::vector<std::unique_ptr<CDFH>> cdvec_t;
0052 
0053   //---------------------------------------------------------------------------
0054   // Map file name to index of CD record
0055   //---------------------------------------------------------------------------
0056   typedef std::unordered_map<std::string, size_t> cdmap_t;
0057 
0058   //---------------------------------------------------------------------------
0059   // Map of Central Directory records
0060   //---------------------------------------------------------------------------
0061   typedef std::unordered_map<std::string, std::unique_ptr<CDFH>> cdrecs_t;
0062 
0063   //---------------------------------------------------------------------------
0064   // A data structure representing the Central Directory File header record
0065   //---------------------------------------------------------------------------
0066   struct CDFH
0067   {
0068     //-------------------------------------------------------------------------
0069     // Parse central directory
0070     // @param buffer      : buffer containing the CD records
0071     // @param bufferSize  : size of the buffer
0072     // @param nbCdRecords : nb of CD records
0073     // @return            : vector of CD records / file name to index mapping
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         // check the signature
0086         uint32_t signature = to<uint32_t>( buffer + offset );
0087         if( signature != cdfhSign ) throw bad_data();
0088         // parse the record
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     // Parse central directory
0101     // @param buffer      : buffer containing the CD records
0102     // @param bufferSize  : size of the buffer
0103     // @return            : vector of CD records / file name to index mapping
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         // check the signature
0114         uint32_t signature = to<uint32_t>( buffer );
0115         if( signature != cdfhSign )
0116           return std::make_tuple( std::move( cdvec ), std::move( cdmap ) );
0117         // parse the record
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     // Calculate size of the Central Directory
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     // Constructor from Local File Header
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     // Constructor from buffer
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       // now parse the 'extra' (may contain the zip64 extension to CDFH)
0219       ParseExtra( buffer + 46 + filenameLength, extraLength );
0220 
0221       cdfhSize = cdfhBaseSize + filenameLength + extraLength + commentLength;
0222     }
0223 
0224     //-------------------------------------------------------------------------
0225     // Choose the right offset value from the CDFH record
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     // Parse the extensible data fields
0236     //-------------------------------------------------------------------------
0237     void ParseExtra( const char *buffer, uint16_t length)
0238     {
0239       uint8_t ovrflws = Extra::NONE;
0240       uint16_t exsize = 0;
0241 
0242       // check if compressed size is overflown
0243       if( compressedSize == ovrflw<uint32_t>::value)
0244       {
0245         ovrflws |= Extra::CPMSIZE;
0246         exsize  += sizeof( uint64_t );
0247       }
0248 
0249       // check if original size is overflown
0250       if( uncompressedSize == ovrflw<uint32_t>::value )
0251       {
0252         ovrflws |= Extra::UCMPSIZE;
0253         exsize  += sizeof( uint64_t );
0254       }
0255 
0256       // check if offset is overflown
0257       if( offset == ovrflw<uint32_t>::value )
0258       {
0259         ovrflws |= Extra::OFFSET;
0260         exsize  += sizeof( uint64_t );
0261       }
0262 
0263       // check if number of disks is overflown
0264       if( nbDisk == ovrflw<uint16_t>::value )
0265       {
0266         ovrflws |= Extra::NBDISK;
0267         exsize  += sizeof( uint32_t );
0268       }
0269 
0270       // if the expected size of ZIP64 extension is 0 we
0271       // can skip parsing of 'extra'
0272       if( exsize == 0 ) return;
0273 
0274       // Parse the extra part
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     //! Serialize the object into a buffer
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     //! @return : true if ZIP64 extension is present, false otherwise
0315     //-------------------------------------------------------------------------
0316     inline bool IsZIP64() const
0317     {
0318       return extra.get();
0319     }
0320 
0321     //-------------------------------------------------------------------------
0322     //! @return : true if the data descriptor flag is on, false otherwise
0323     //-------------------------------------------------------------------------
0324     bool HasDataDescriptor()
0325     {
0326       return generalBitFlag & DataDescriptor::flag;
0327     }
0328 
0329     uint16_t                zipVersion;        // ZIP version
0330     uint16_t                minZipVersion;     //< minumum ZIP version
0331     uint16_t                generalBitFlag;    //< flags
0332     uint16_t                compressionMethod; //< compression method
0333     dos_timestmp            timestmp;          //< DOS timestamp
0334     uint32_t                ZCRC32;            //< CRC32
0335     uint32_t                compressedSize;    //< compressed size
0336     uint32_t                uncompressedSize;  //< uncompressed size
0337     uint16_t                filenameLength;    //< filename length
0338     uint16_t                extraLength;       //< size of the ZIP64 extra field
0339     uint16_t                commentLength;     //< comment length
0340     uint16_t                nbDisk;            //< number of disks
0341     uint16_t                internAttr;        //< internal attributes
0342     uint32_t                externAttr;        //< external attributes
0343     uint32_t                offset;            //< offset
0344     std::string             filename;          //< file name
0345     std::unique_ptr<Extra>  extra;             //< ZIP64 extra field
0346     std::string             comment;           //< user comment
0347     uint16_t                cdfhSize;          // size of the record
0348 
0349     //-------------------------------------------------------------------------
0350     // the Central Directory File Header signature
0351     //-------------------------------------------------------------------------
0352     static const uint32_t cdfhSign = 0x02014b50;
0353     static const uint16_t cdfhBaseSize = 46;
0354   };
0355 }
0356 
0357 #endif /* SRC_XRDZIP_XRDZIPCDFH_HH_ */