blob: 3cf1a9e293b12b67e1d6401f83128556292fa6ed [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_filter.hxx"
/*
#include <tools/datetime.hxx>
*/
#include <osl/diagnose.h>
#include <rtl/crc.h>
#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<sal_uInt32>(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<sal_Int32>(nCdOffset), static_cast<sal_Int32>(nCdSize));
}
}
}
std::vector< ZipEntry* >::iterator aIter( maEntries.begin() );
while( aIter != maEntries.end() )
{
delete (*aIter++);
}
mbOpen = false;
return !isError();
}