//------------------------------------------------------------------------------ // Copyright (c) 2011-2014 by European Organization for Nuclear Research (CERN) // Author: Michal Simon //------------------------------------------------------------------------------ // This file is part of the XRootD software suite. // // XRootD is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // XRootD is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with XRootD. If not, see . // // In applying this licence, CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. //------------------------------------------------------------------------------ #ifndef SRC_XRDZIP_XRDZIPLFH_HH_ #define SRC_XRDZIP_XRDZIPLFH_HH_ #include "XrdZip/XrdZipUtils.hh" #include "XrdZip/XrdZipExtra.hh" #include #include #include #include namespace XrdZip { //--------------------------------------------------------------------------- //! A data structure representing ZIP Local File Header //--------------------------------------------------------------------------- struct LFH { //------------------------------------------------------------------------- //! Convenience function for initializing compressed/uncompressed size //------------------------------------------------------------------------- inline static uint32_t initSize( const off_t &fileSize ) { return fileSize >= ovrflw::value ? ovrflw::value : fileSize; } //------------------------------------------------------------------------- //! Constructor //------------------------------------------------------------------------- LFH( const std::string &filename, uint32_t crc, off_t fileSize, time_t time ) : generalBitFlag( 0 ), compressionMethod( 0 ), timestmp( time ), ZCRC32( crc ), compressedSize( initSize( fileSize ) ), uncompressedSize( initSize( fileSize ) ), filenameLength( filename.size() ), filename( filename ), extra( new Extra( fileSize ) ) { extraLength = extra->totalSize; if ( extraLength == 0 ) minZipVersion = 10; else minZipVersion = 45; lfhSize = lfhBaseSize + filenameLength + extraLength; } //------------------------------------------------------------------------- //! Constructor from buffer //------------------------------------------------------------------------- LFH( const char *buffer, const uint64_t bufferSize = 0 ) { if(bufferSize > 0 && bufferSize < (uint64_t)lfhBaseSize) throw bad_data(); // check if the buffer contains a LFH record uint32_t signature = 0; from_buffer( signature, buffer ); if( signature != lfhSign ) throw bad_data(); // parse LFH filds from_buffer( minZipVersion, buffer ); from_buffer( generalBitFlag, buffer ); from_buffer( compressionMethod, buffer ); from_buffer( timestmp, buffer ); from_buffer( ZCRC32, buffer ); from_buffer( compressedSize, buffer ); from_buffer( uncompressedSize, buffer ); from_buffer( filenameLength, buffer ); from_buffer( extraLength, buffer ); if(bufferSize > 0 && (uint64_t)(lfhBaseSize + filenameLength + extraLength) > bufferSize) throw bad_data(); // parse the filename filename.assign( buffer, filenameLength ); buffer += filenameLength; // parse the extra record if( extraLength > 0 ) ParseExtra( buffer, extraLength ); lfhSize = lfhBaseSize + filenameLength + extraLength; } //------------------------------------------------------------------------- //! Serialize the object into a buffer //------------------------------------------------------------------------- void Serialize( buffer_t &buffer ) { copy_bytes( lfhSign, buffer ); copy_bytes( minZipVersion, buffer ); copy_bytes( generalBitFlag, buffer ); copy_bytes( compressionMethod, buffer ); copy_bytes( timestmp.time, buffer ); copy_bytes( timestmp.date, buffer ); copy_bytes( ZCRC32, buffer ); copy_bytes( compressedSize, buffer ); copy_bytes( uncompressedSize, buffer ); copy_bytes( filenameLength, buffer ); copy_bytes( extraLength , buffer ); std::copy( filename.begin(), filename.end(), std::back_inserter( buffer ) ); extra->Serialize( buffer ); } //------------------------------------------------------------------------- // Parse the extensible data fields //------------------------------------------------------------------------- void ParseExtra( const char *buffer, uint16_t length) { uint8_t ovrflws = Extra::NONE; uint16_t exsize = 0; // check if compressed size is overflown if( compressedSize == ovrflw::value) { ovrflws |= Extra::CPMSIZE; exsize += sizeof( uint64_t ); } // check if original size is overflown if( uncompressedSize == ovrflw::value ) { ovrflws |= Extra::UCMPSIZE; exsize += sizeof( uint64_t ); } // if the expected size of ZIP64 extension is 0 we // can skip parsing of 'extra' if( exsize == 0 ) return; extra.reset( new Extra() ); // Parse the extra part buffer = Extra::Find( buffer, length ); if( buffer ) extra->FromBuffer( buffer, exsize, ovrflws ); } uint16_t minZipVersion; //< minimum ZIP version required to read the file uint16_t generalBitFlag; //< flags uint16_t compressionMethod; //< compression method dos_timestmp timestmp; //< DOS time stamp uint32_t ZCRC32; //< crc32 value uint32_t compressedSize; //< compressed data size uint32_t uncompressedSize; //< uncompressed data size uint16_t filenameLength; //< file name length uint16_t extraLength; //< size of the ZIP64 extra field std::string filename; //< file name std::unique_ptr extra; //< the ZIP64 extra field uint16_t lfhSize; //< size of the Local File Header //------------------------------------------------------------------------- //! Local File Header signature //------------------------------------------------------------------------- static const uint32_t lfhSign = 0x04034b50; static const uint16_t lfhBaseSize = 30; }; } #endif /* SRC_XRDZIP_XRDZIPLFH_HH_ */