/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2008 by Sun Microsystems, Inc. * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: zip.cxx,v $ * $Revision: 1.7 $ * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org 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 Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_filter.hxx" /* #include */ #include #include #include "zip.hxx" #include "zipfile.hxx" using namespace rtl; /** this struct describes one entry in a zip file */ struct ZipEntry { OString name; /* the name we used */ sal_Int32 offset; /* where the header starts */ sal_Int32 endOffset; /* where the file data ends */ sal_Int32 crc; sal_Int32 modTime; /* dos mod time & date */ sal_Int32 fileLen; /* file size, in bytes */ }; /** put one byte inside this stream */ static osl::File::RC putC( unsigned char c, osl::File& rFile ) { sal_uInt64 nBytesWritten; osl::File::RC nRC = rFile.write( &c, 1, nBytesWritten ); OSL_ASSERT( nBytesWritten == 1 ); return nRC; } /** write a short to the ZipFile */ void ZipFile::writeShort( sal_Int16 s) { if( !isError() ) { mnRC = putC( static_cast< unsigned char >( s & 0xff ), mrFile ); if( !isError() ) mnRC = putC( static_cast< unsigned char >( (s >> 8) & 0xff ), mrFile ); } } /** write a long to the ZipFile */ void ZipFile::writeLong( sal_Int32 l ) { if( !isError() ) { mnRC = putC( static_cast< unsigned char >( l & 0xff ), mrFile); if( !isError() ) { mnRC = putC( static_cast< unsigned char >( (l >> 8) & 0xff ), mrFile); if( !isError() ) { mnRC = putC( static_cast< unsigned char >( (l >> 16) & 0xff ), mrFile); if( !isError() ) { mnRC = putC( static_cast< unsigned char >( (l >> 24) & 0xff ), mrFile); } } } } } /** copy the zipentries file to the zipfile and updates the crc of that zipentry */ void ZipFile::copyAndCRC(ZipEntry *e, osl::File& rFile) { char buf[2048]; sal_uInt64 n, nWritten; e->crc = rtl_crc32( 0, 0L, 0 ); while( !isError() ) { mnRC = rFile.read( buf, sizeof(buf), n ); if(n == 0) break; if( !isError() ) { sal_uInt32 nTemp = static_cast(n); e->crc = rtl_crc32( e->crc, (const void *) buf, nTemp ); mnRC = mrFile.write( buf, n, nWritten ); OSL_ASSERT( n == nWritten ); } } if( !isError() ) { sal_uInt64 nPosition = 0; mnRC = mrFile.getPos( nPosition ); if( !isError() ) { e->endOffset = static_cast< sal_Int32 >( nPosition ); } } } /** write a yet empty local header for a zipentry to the zipfile */ void ZipFile::writeDummyLocalHeader(ZipEntry *e) { sal_Int32 len = zf_lfhSIZE + e->name.getLength(); sal_Int32 i; sal_uInt64 nPosition = 0; mnRC = mrFile.getPos( nPosition ); if( !isError() ) { e->offset = static_cast< sal_Int32 >( nPosition ); for (i = 0; (i < len) && !isError(); ++i) mnRC = putC(0, mrFile); } } /** write the local header for a zipentry to the zipfile */ void ZipFile::writeLocalHeader(ZipEntry *e) { TimeValue aTime; osl_getSystemTime( &aTime ); oslDateTime aDate; osl_getDateTimeFromTimeValue( &aTime, &aDate ); e->modTime = ((aDate.Year - 1980) << 25) | (aDate.Month << 21) | (aDate.Day << 16) | (aDate.Hours << 11) | (aDate.Minutes << 5) | (aDate.Seconds >> 1); e->fileLen = e->endOffset - e->offset - zf_lfhSIZE - e->name.getLength(); if(!isError()) { mnRC = mrFile.setPos( Pos_Absolut, e->offset ); writeLong(zf_LFHSIGValue); // magic number writeShort(zf_Vers(1, 0)); // extract version writeShort(0); // flags writeShort(zf_compNone); // compression method writeLong(e->modTime); // file mod date & time writeLong(e->crc); // file crc writeLong(e->fileLen); // compressed size writeLong(e->fileLen); // uncompressed size writeShort((sal_Int16) e->name.getLength()); // name length writeShort(0); // extra length field if( !isError() ) { sal_uInt64 nWritten; mnRC = mrFile.write( e->name.getStr(), e->name.getLength(), nWritten ); // file name OSL_ASSERT( nWritten == (sal_uInt64)e->name.getLength() ); if( !isError() ) { mnRC = mrFile.setPos( Pos_Absolut, e->endOffset ); } } } } /* write a zipentry in the central dir to the zipfile */ void ZipFile::writeCentralDir(ZipEntry *e) { writeLong(zf_CDHSIGValue); // magic number writeShort(zf_Vers(1, 0)); // version made by writeShort(zf_Vers(1, 0)); // vers to extract writeShort(0); // flags writeShort(zf_compNone); // compression method writeLong(e->modTime); // file mod time & date writeLong(e->crc); writeLong(e->fileLen); // compressed file size writeLong(e->fileLen); // uncompressed file size writeShort((sal_Int16) e->name.getLength()); // name length writeShort(0); // extra field length writeShort(0); // file comment length writeShort(0); // disk number start writeShort(0); // internal file attributes writeLong(0); // external file attributes writeLong(e->offset); // offset w.r.t disk if( !isError() ) { sal_uInt64 nWritten; mrFile.write( e->name.getStr(), e->name.getLength(), nWritten ); // file name OSL_ASSERT( nWritten == (sal_uInt64)e->name.getLength() ); } } /* write the end of the central dir to the zipfile */ void ZipFile::writeEndCentralDir(sal_Int32 nCdOffset, sal_Int32 nCdSize) { writeLong(zf_ECDSIGValue); // magic number writeShort(0); // disk num writeShort(0); // disk with central dir writeShort( static_cast< sal_Int16 >( maEntries.size() ) ); // number of file entries writeShort( static_cast< sal_Int16 >( maEntries.size() ) ); // number of file entries writeLong(nCdSize); // central dir size writeLong(nCdOffset); writeShort(0); // comment len } /**************************************************************** * The exported functions ****************************************************************/ /* Create a zip file for writing, return a handle for it. * RETURNS: A new zip-file output object, or NULL if it failed, in * which case *errMsgBuffer will contain an error message string. */ ZipFile::ZipFile(osl::File& rFile ) : mrFile( rFile ), mbOpen( true ), mnRC( osl::File::E_None ) { } ZipFile::~ZipFile() { if( mbOpen ) close(); } /* Add a file to this zip with the given name. * RETURNS: true if successful, else false. If false, the caller should * call zip_Close() and delete the bum zip file. */ bool ZipFile::addFile( osl::File& rFile, const OString& rName ) { OSL_ASSERT( mbOpen ); if( !mbOpen ) return false; OSL_ASSERT( 0 != rName.getLength() ); if(0 == rName.getLength()) return false; mnRC = rFile.open( osl_File_OpenFlag_Read ); if( !isError() ) { ZipEntry *e = new ZipEntry; e->name = rName; maEntries.push_back(e); writeDummyLocalHeader(e); if( !isError() ) { copyAndCRC(e, rFile); if(!isError()) { writeLocalHeader(e); } } rFile.close(); } return !isError(); } /* Finish up the zip file, close it, and deallocate the zip file object. * RETURNS: true if successful, else false. */ bool ZipFile::close() { OSL_ASSERT( mbOpen ); if( !mbOpen ) return false; if( !isError() ) { sal_uInt64 nCdOffset; mrFile.getPos( nCdOffset ); std::vector< ZipEntry* >::iterator aIter( maEntries.begin() ); while((aIter != maEntries.end()) && !isError()) { writeCentralDir( (*aIter++) ); } if( !isError() ) { sal_uInt64 nCdSize; mrFile.getPos( nCdSize ); nCdSize -= nCdOffset; if( !isError() ) { writeEndCentralDir(static_cast(nCdOffset), static_cast(nCdSize)); } } } std::vector< ZipEntry* >::iterator aIter( maEntries.begin() ); while( aIter != maEntries.end() ) { delete (*aIter++); } mbOpen = false; return !isError(); }