LCOV - code coverage report
Current view: top level - libreoffice/workdir/unxlngi6.pro/UnpackedTarball/cdr/src/lib - CDRZipStream.cpp (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 192 0.0 %
Date: 2012-12-17 Functions: 0 26 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* libcdr
       3             :  * Version: MPL 1.1 / GPLv2+ / LGPLv2+
       4             :  *
       5             :  * The contents of this file are subject to the Mozilla Public License Version
       6             :  * 1.1 (the "License"); you may not use this file except in compliance with
       7             :  * the License or as specified alternatively below. You may obtain a copy of
       8             :  * the License at http://www.mozilla.org/MPL/
       9             :  *
      10             :  * Software distributed under the License is distributed on an "AS IS" basis,
      11             :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12             :  * for the specific language governing rights and limitations under the
      13             :  * License.
      14             :  *
      15             :  * Major Contributor(s):
      16             :  * Copyright (C) 2012 Fridrich Strba <fridrich.strba@bluewin.ch>
      17             :  * Copyright (C) 2011 Eilidh McAdam <tibbylickle@gmail.com>
      18             :  *
      19             :  *
      20             :  * All Rights Reserved.
      21             :  *
      22             :  * For minor contributions see the git repository.
      23             :  *
      24             :  * Alternatively, the contents of this file may be used under the terms of
      25             :  * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
      26             :  * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
      27             :  * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
      28             :  * instead of those above.
      29             :  */
      30             : 
      31             : 
      32             : #include <string.h>
      33             : #include <zlib.h>
      34             : #include <map>
      35             : #include <libwpd-stream/libwpd-stream.h>
      36             : #include "CDRZipStream.h"
      37             : #include "CDRInternalStream.h"
      38             : #include "libcdr_utils.h"
      39             : 
      40             : namespace
      41             : {
      42             : 
      43             : struct LocalFileHeader
      44             : {
      45             :   unsigned short general_flag;
      46             :   unsigned short compression;
      47             :   unsigned crc32;
      48             :   unsigned compressed_size;
      49             :   unsigned uncompressed_size;
      50             :   std::string filename;
      51           0 :   LocalFileHeader()
      52           0 :     : general_flag(0), compression(0), crc32(0), compressed_size(0), uncompressed_size(0), filename() {}
      53           0 :   ~LocalFileHeader() {}
      54             : };
      55             : 
      56           0 : struct CentralDirectoryEntry
      57             : {
      58             :   unsigned short general_flag;
      59             :   unsigned short compression;
      60             :   unsigned crc32;
      61             :   unsigned compressed_size;
      62             :   unsigned uncompressed_size;
      63             :   unsigned offset;
      64             :   std::string filename;
      65           0 :   CentralDirectoryEntry()
      66           0 :     : general_flag(0), compression(0), crc32(0), compressed_size(0), uncompressed_size(0), offset(0), filename() {}
      67           0 :   ~CentralDirectoryEntry() {}
      68             : };
      69             : 
      70             : struct CentralDirectoryEnd
      71             : {
      72             :   unsigned cdir_size;
      73             :   unsigned cdir_offset;
      74           0 :   CentralDirectoryEnd()
      75           0 :     : cdir_size(0), cdir_offset(0) {}
      76           0 :   ~CentralDirectoryEnd() {}
      77             : };
      78             : 
      79             : } // anonymous namespace
      80             : 
      81             : namespace libcdr
      82             : {
      83             : 
      84             : struct CDRZipStreamImpl
      85             : {
      86             :   WPXInputStream *m_input;
      87             :   unsigned m_cdir_offset;
      88             :   std::map<std::string, CentralDirectoryEntry> m_cdir;
      89             :   bool m_initialized;
      90           0 :   CDRZipStreamImpl(WPXInputStream *input)
      91           0 :     : m_input(input), m_cdir_offset(0), m_cdir(), m_initialized(false) {}
      92           0 :   ~CDRZipStreamImpl() {}
      93             : 
      94             :   bool isZipStream();
      95             :   WPXInputStream *getSubstream(const char *name);
      96             : private:
      97             :   CDRZipStreamImpl(const CDRZipStreamImpl &);
      98             :   CDRZipStreamImpl &operator=(const CDRZipStreamImpl &);
      99             : 
     100             :   bool findCentralDirectoryEnd();
     101             :   bool readCentralDirectoryEnd(CentralDirectoryEnd &end);
     102             :   bool readCentralDirectory(const CentralDirectoryEnd &end);
     103             :   bool readLocalFileHeader(LocalFileHeader &header);
     104             :   bool areHeadersConsistent(const LocalFileHeader &header, const CentralDirectoryEntry &entry);
     105             : };
     106             : 
     107             : } // namespace libcdr
     108             : 
     109             : 
     110             : using namespace libcdr;
     111             : 
     112             : 
     113           0 : libcdr::CDRZipStream::CDRZipStream(WPXInputStream *input) :
     114             :   WPXInputStream(),
     115           0 :   m_pImpl(new CDRZipStreamImpl(input))
     116             : {
     117           0 : }
     118             : 
     119           0 : libcdr::CDRZipStream::~CDRZipStream()
     120             : {
     121           0 :   if (m_pImpl)
     122           0 :     delete m_pImpl;
     123           0 : }
     124             : 
     125           0 : const unsigned char *libcdr::CDRZipStream::read(unsigned long numBytes, unsigned long &numBytesRead)
     126             : {
     127           0 :   return m_pImpl->m_input->read(numBytes, numBytesRead);
     128             : }
     129             : 
     130           0 : int libcdr::CDRZipStream::seek(long offset, WPX_SEEK_TYPE seekType)
     131             : {
     132           0 :   return m_pImpl->m_input->seek(offset, seekType);
     133             : }
     134             : 
     135           0 : long libcdr::CDRZipStream::tell()
     136             : {
     137           0 :   return m_pImpl->m_input->tell();
     138             : }
     139             : 
     140           0 : bool libcdr::CDRZipStream::atEOS()
     141             : {
     142           0 :   return m_pImpl->m_input->atEOS();
     143             : }
     144             : 
     145           0 : bool libcdr::CDRZipStream::isOLEStream()
     146             : {
     147           0 :   return m_pImpl->isZipStream();
     148             : }
     149             : 
     150           0 : WPXInputStream *libcdr::CDRZipStream::getDocumentOLEStream(const char *name)
     151             : {
     152           0 :   if (!m_pImpl->isZipStream())
     153           0 :     return 0;
     154           0 :   return m_pImpl->getSubstream(name);
     155             : }
     156             : 
     157             : #define CDIR_ENTRY_SIG 0x02014b50
     158             : #define LOC_FILE_HEADER_SIG 0x04034b50
     159             : #define CDIR_END_SIG 0x06054b50
     160             : 
     161           0 : bool libcdr::CDRZipStreamImpl::findCentralDirectoryEnd()
     162             : {
     163             : #if defined(LIBWPD_STREAM_VERSION_MAJOR) && defined(LIBWPD_STREAM_VERSION_MINOR) && defined(LIBWPD_STREAM_VERSION_REVISION) \
     164             :   && (LIBWPD_STREAM_VERSION_MAJOR > 0 || (LIBWPD_STREAM_VERSION_MAJOR == 0 && (LIBWPD_STREAM_VERSION_MINOR > 9 \
     165             :   || (LIBWPD_STREAM_VERSION_MINOR == 9 && LIBWPD_STREAM_VERSION_REVISION >= 5))))
     166             :   if (m_cdir_offset || m_input->seek(-1024, WPX_SEEK_END))
     167             : #endif
     168           0 :     m_input->seek(m_cdir_offset, WPX_SEEK_SET);
     169             :   try
     170             :   {
     171           0 :     while (!m_input->atEOS())
     172             :     {
     173           0 :       unsigned signature = readU32(m_input);
     174           0 :       if (signature == CDIR_END_SIG)
     175             :       {
     176           0 :         m_input->seek(-4, WPX_SEEK_CUR);
     177           0 :         m_cdir_offset = m_input->tell();
     178           0 :         return true;
     179             :       }
     180             :       else
     181           0 :         m_input->seek(-3, WPX_SEEK_CUR);
     182             :     }
     183             :   }
     184           0 :   catch (...)
     185             :   {
     186           0 :     return false;
     187             :   }
     188           0 :   return false;
     189             : }
     190             : 
     191           0 : bool libcdr::CDRZipStreamImpl::isZipStream()
     192             : {
     193           0 :   if (m_cdir_offset)
     194             :   {
     195           0 :     if(m_cdir.empty())
     196           0 :       return false;
     197           0 :     return true;
     198             :   }
     199           0 :   if (m_initialized)
     200           0 :     return false;
     201           0 :   m_initialized = true;
     202           0 :   if (!findCentralDirectoryEnd())
     203           0 :     return false;
     204           0 :   CentralDirectoryEnd end;
     205           0 :   if (!readCentralDirectoryEnd(end))
     206           0 :     return false;
     207           0 :   if (!readCentralDirectory(end))
     208           0 :     return false;
     209           0 :   CentralDirectoryEntry entry = m_cdir.begin()->second;
     210           0 :   m_input->seek(entry.offset, WPX_SEEK_SET);
     211           0 :   LocalFileHeader header;
     212           0 :   if (!readLocalFileHeader(header))
     213           0 :     return false;
     214           0 :   if (!areHeadersConsistent(header, entry))
     215           0 :     return false;
     216           0 :   return true;
     217             : }
     218             : 
     219           0 : bool libcdr::CDRZipStreamImpl::readCentralDirectory(const CentralDirectoryEnd &end)
     220             : {
     221             :   try
     222             :   {
     223           0 :     m_input->seek(end.cdir_offset, WPX_SEEK_SET);
     224           0 :     while (!m_input->atEOS())
     225             :     {
     226           0 :       unsigned signature = readU32(m_input);
     227           0 :       if (signature != CDIR_ENTRY_SIG)
     228             :       {
     229           0 :         if (m_cdir.empty())
     230           0 :           return false;
     231             :         else
     232           0 :           return true;
     233             :       }
     234             : 
     235           0 :       CentralDirectoryEntry entry;
     236           0 :       m_input->seek(4, WPX_SEEK_CUR);
     237           0 :       entry.general_flag = readU16(m_input);
     238           0 :       entry.compression = readU16(m_input);
     239           0 :       m_input->seek(4, WPX_SEEK_CUR);
     240           0 :       entry.crc32 = readU32(m_input);
     241           0 :       entry.compressed_size = readU32(m_input);
     242           0 :       entry.uncompressed_size = readU32(m_input);
     243           0 :       unsigned short filename_size = readU16(m_input);
     244           0 :       unsigned short extra_field_size = readU16(m_input);
     245           0 :       unsigned short file_comment_size = readU16(m_input);
     246           0 :       m_input->seek(8, WPX_SEEK_CUR);
     247           0 :       entry.offset = readU32(m_input);
     248           0 :       entry.filename.clear();
     249           0 :       entry.filename.reserve(filename_size);
     250           0 :       unsigned long bytesRead = 0;
     251           0 :       const unsigned char *buffer = m_input->read(filename_size, bytesRead);
     252           0 :       entry.filename.assign((const char *)buffer, bytesRead);
     253           0 :       m_input->seek(extra_field_size+file_comment_size, WPX_SEEK_CUR);
     254             : 
     255           0 :       m_cdir[entry.filename] = entry;
     256           0 :     }
     257             :   }
     258           0 :   catch (...)
     259             :   {
     260           0 :     return false;
     261             :   }
     262           0 :   return true;
     263             : }
     264             : 
     265           0 : WPXInputStream *libcdr::CDRZipStreamImpl::getSubstream(const char *name)
     266             : {
     267           0 :   if (m_cdir.empty())
     268           0 :     return 0;
     269           0 :   std::map<std::string, CentralDirectoryEntry>::const_iterator iter = m_cdir.lower_bound(name);
     270           0 :   if (iter == m_cdir.end())
     271           0 :     return 0;
     272           0 :   if (m_cdir.key_comp()(name, iter->first))
     273             :   {
     274           0 :     size_t name_length = strlen(name);
     275           0 :     if (iter->first.compare(0, name_length, name))
     276           0 :       return 0;
     277             :   }
     278           0 :   CentralDirectoryEntry entry = iter->second;
     279           0 :   m_input->seek(entry.offset, WPX_SEEK_SET);
     280           0 :   LocalFileHeader header;
     281           0 :   if (!readLocalFileHeader(header))
     282           0 :     return 0;
     283           0 :   if (!areHeadersConsistent(header, entry))
     284           0 :     return 0;
     285           0 :   if (!entry.compression)
     286           0 :     return new CDRInternalStream(m_input, entry.compressed_size);
     287             :   else
     288             :   {
     289             :     int ret;
     290             :     z_stream strm;
     291             : 
     292             :     /* allocate inflate state */
     293           0 :     strm.zalloc = Z_NULL;
     294           0 :     strm.zfree = Z_NULL;
     295           0 :     strm.opaque = Z_NULL;
     296           0 :     strm.avail_in = 0;
     297           0 :     strm.next_in = Z_NULL;
     298           0 :     ret = inflateInit2(&strm,-MAX_WBITS);
     299           0 :     if (ret != Z_OK)
     300           0 :       return 0;
     301             : 
     302           0 :     unsigned long numBytesRead = 0;
     303           0 :     const unsigned char *compressedData = m_input->read(entry.compressed_size, numBytesRead);
     304           0 :     if (numBytesRead != entry.compressed_size)
     305           0 :       return 0;
     306             : 
     307           0 :     strm.avail_in = numBytesRead;
     308           0 :     strm.next_in = (Bytef *)compressedData;
     309             : 
     310           0 :     std::vector<unsigned char>data(entry.uncompressed_size);
     311             : 
     312           0 :     strm.avail_out = entry.uncompressed_size;
     313           0 :     strm.next_out = reinterpret_cast<Bytef *>(&data[0]);
     314           0 :     ret = inflate(&strm, Z_FINISH);
     315           0 :     switch (ret)
     316             :     {
     317             :     case Z_NEED_DICT:
     318             :     case Z_DATA_ERROR:
     319             :     case Z_MEM_ERROR:
     320           0 :       (void)inflateEnd(&strm);
     321           0 :       data.clear();
     322           0 :       return 0;
     323             :     }
     324           0 :     (void)inflateEnd(&strm);
     325           0 :     return new CDRInternalStream(data);
     326           0 :   }
     327             : }
     328             : 
     329           0 : bool libcdr::CDRZipStreamImpl::readCentralDirectoryEnd(CentralDirectoryEnd &end)
     330             : {
     331             :   try
     332             :   {
     333           0 :     unsigned signature = readU32(m_input);
     334           0 :     if (signature != CDIR_END_SIG)
     335           0 :       return false;
     336             : 
     337           0 :     m_input->seek(8, WPX_SEEK_CUR);
     338           0 :     end.cdir_size = readU32(m_input);
     339           0 :     end.cdir_offset = readU32(m_input);
     340           0 :     unsigned short comment_size = readU16(m_input);
     341           0 :     m_input->seek(comment_size, WPX_SEEK_CUR);
     342             :   }
     343           0 :   catch (...)
     344             :   {
     345           0 :     return false;
     346             :   }
     347           0 :   return true;
     348             : }
     349             : 
     350           0 : bool libcdr::CDRZipStreamImpl::readLocalFileHeader(LocalFileHeader &header)
     351             : {
     352             :   try
     353             :   {
     354           0 :     unsigned signature = readU32(m_input);
     355           0 :     if (signature != LOC_FILE_HEADER_SIG)
     356           0 :       return false;
     357             : 
     358           0 :     m_input->seek(2, WPX_SEEK_CUR);
     359           0 :     header.general_flag = readU16(m_input);
     360           0 :     header.compression = readU16(m_input);
     361           0 :     m_input->seek(4, WPX_SEEK_CUR);
     362           0 :     header.crc32 = readU32(m_input);
     363           0 :     header.compressed_size = readU32(m_input);
     364           0 :     header.uncompressed_size = readU32(m_input);
     365           0 :     unsigned short filename_size = readU16(m_input);
     366           0 :     unsigned short extra_field_size = readU16(m_input);
     367           0 :     header.filename.clear();
     368           0 :     header.filename.reserve(filename_size);
     369           0 :     unsigned long bytesRead = 0;
     370           0 :     const unsigned char *buffer = m_input->read(filename_size, bytesRead);
     371           0 :     header.filename.assign((const char *)buffer, bytesRead);
     372           0 :     m_input->seek(extra_field_size, WPX_SEEK_CUR);
     373             :   }
     374           0 :   catch (...)
     375             :   {
     376           0 :     return false;
     377             :   }
     378           0 :   return true;
     379             : }
     380             : 
     381           0 : bool libcdr::CDRZipStreamImpl::areHeadersConsistent(const LocalFileHeader &header, const CentralDirectoryEntry &entry)
     382             : {
     383           0 :   if (header.general_flag != entry.general_flag)
     384           0 :     return false;
     385           0 :   if (header.compression != entry.compression)
     386           0 :     return false;
     387           0 :   if (!(header.general_flag & 0x08))
     388             :   {
     389           0 :     if (header.crc32 != entry.crc32)
     390           0 :       return false;
     391           0 :     if (header.compressed_size != entry.compressed_size)
     392           0 :       return false;
     393           0 :     if (header.uncompressed_size != entry.uncompressed_size)
     394           0 :       return false;
     395             :   }
     396           0 :   return true;
     397             : }
     398             : 
     399             : 
     400             : /* vim:set shiftwidth=2 softtabstop=2 expandtab: */

Generated by: LCOV version 1.10