Added linux makefiles

This commit is contained in:
Luiz Rafael Culik
2004-04-03 04:29:41 +00:00
parent 423790ecba
commit 0f62fcf919
14 changed files with 6223 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
////////////////////////////////////////////////////////////////////////////////
// $Workfile: ZipString.cpp $
// $Archive: /ZipArchive/ZipString.cpp $
// $Date$ $Author$
////////////////////////////////////////////////////////////////////////////////
// This source file is part of the ZipArchive library source distribution and
// is Copyright 2000-2003 by Tadeusz Dracz (http://www.artpol-software.com/)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// For the licensing details see the file License.txt
////////////////////////////////////////////////////////////////////////////////
#include "zipstring.h"
ZIPSTRINGCOMPARE GetCZipStrCompFunc(bool bCaseSensitive, bool bCollate)
{
if (bCollate)
return bCaseSensitive ? & CZipString::Collate : & CZipString::CollateNoCase;
else
return bCaseSensitive ? & CZipString::Compare : & CZipString::CompareNoCase;
}

View File

@@ -0,0 +1,20 @@
///////////////////////////////////////////////////////////////////////////////
// $Workfile: stdafx.cpp $
// $Archive: /ZipArchive/stdafx.cpp $
// $Date$ $Author$
////////////////////////////////////////////////////////////////////////////////
// This source file is part of the ZipArchive library source distribution and
// is Copyright 2000-2003 by Tadeusz Dracz (http://www.artpol-software.com/)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// For the licensing details see the file License.txt
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,108 @@
///////////////////////////////////////////////////////////////////////////////
// $Workfile: ZipAutoBuffer.cpp $
// $Archive: /ZipArchive_STL/ZipAutoBuffer.cpp $
// $Date$ $Author$
////////////////////////////////////////////////////////////////////////////////
// This source file is part of the ZipArchive library source distribution and
// is Copyright 2000-2003 by Tadeusz Dracz (http://www.artpol-software.com/)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// For the licensing details see the file License.txt
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "zipautobuffer.h"
#include <memory.h>
// #ifdef _DEBUG
// #undef THIS_FILE
// static char THIS_FILE[]=__FILE__;
// #define new DEBUG_NEW
// #endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CZipAutoBuffer::CZipAutoBuffer()
{
m_iSize = 0;
m_pBuffer = NULL;
}
CZipAutoBuffer::CZipAutoBuffer(DWORD iSize, bool bZeroMemory)
{
m_iSize = 0;
m_pBuffer = NULL;
Allocate(iSize, bZeroMemory);
}
CZipAutoBuffer::~CZipAutoBuffer()
{
Release();
}
void CZipAutoBuffer::Release()
{
if (m_pBuffer)
{
delete [] m_pBuffer;
m_iSize = 0;
m_pBuffer = NULL;
}
}
char* CZipAutoBuffer::Allocate(DWORD iSize, bool bZeroMemory)
{
if (iSize != m_iSize)
Release();
else
{
if (bZeroMemory)
memset(m_pBuffer, 0, iSize); // zerowanie bufora
return m_pBuffer;
}
if (iSize > 0)
{
m_pBuffer = new char [iSize];
if (bZeroMemory)
memset(m_pBuffer, 0, iSize); // zerowanie bufora
m_iSize = iSize;
}
else
m_pBuffer = NULL;
return m_pBuffer;
}
CZipAutoBuffer::CZipAutoBuffer(const CZipAutoBuffer& buffer)
{
m_pBuffer = NULL;
m_iSize = 0;
if (buffer.m_pBuffer)
{
Allocate(buffer.m_iSize);
memcpy(m_pBuffer, buffer.m_pBuffer, buffer.m_iSize);
}
}
CZipAutoBuffer& CZipAutoBuffer::operator=(const CZipAutoBuffer& buffer)
{
if (this == &buffer)
return *this;
Release();
if (buffer.m_pBuffer)
{
Allocate(buffer.m_iSize);
memcpy(m_pBuffer, buffer.m_pBuffer, buffer.m_iSize);
}
return *this;
}

View File

@@ -0,0 +1,852 @@
///////////////////////////////////////////////////////////////////////////////
// $Workfile: ZipCentralDir.cpp $
// $Archive: /ZipArchive/ZipCentralDir.cpp $
// $Date$ $Author$
////////////////////////////////////////////////////////////////////////////////
// This source file is part of the ZipArchive library source distribution and
// is Copyright 2000-2003 by Tadeusz Dracz (http://www.artpol-software.com/)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// For the licensing details see the file License.txt
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "zipcentraldir.h"
#include "ziparchive.h"
#include "zipfilemapping.h"
#include "zipplatform.h"
#define CENTRALDIRSIZE 22
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
char CZipCentralDir::m_gszSignature[] = {0x50, 0x4b, 0x05, 0x06};
CZipCentralDir::CZipCentralDir()
{
m_bConvertAfterOpen = true;
m_bFindFastEnabled = false;
m_bCaseSensitive = false;
m_pCompare = GetCZipStrCompFunc(ZipPlatform::GetSystemCaseSensitivity());
m_pStorage = NULL;
m_pOpenedFile = NULL;
m_iBufferSize = 32768;
}
void CZipCentralDir::Init()
{
m_info.m_bOnDisk = false;
m_info.m_uBytesBeforeZip = m_info.m_uCentrDirPos = 0;
m_pOpenedFile = NULL;
m_pszComment.Release();
}
CZipCentralDir::~CZipCentralDir()
{
Clear();
}
void CZipCentralDir::Read()
{
ASSERT(m_pStorage);
WORD uCommentSize;
m_info.m_uCentrDirPos = Locate();
m_pStorage->m_pFile->Seek(m_info.m_uCentrDirPos, CZipAbstractFile::begin);
CZipAutoBuffer buf(CENTRALDIRSIZE);
int uRead = m_pStorage->m_pFile->Read(buf, CENTRALDIRSIZE);
if (uRead != CENTRALDIRSIZE)
ThrowError(CZipException::badZipFile);
memcpy(&m_szSignature, buf, 4);
memcpy(&m_info.m_uThisDisk, buf + 4, 2);
memcpy(&m_info.m_uDiskWithCD, buf + 6, 2);
memcpy(&m_info.m_uDiskEntriesNo,buf + 8, 2);
memcpy(&m_info.m_uEntriesNumber,buf + 10, 2);
memcpy(&m_info.m_uSize, buf + 12, 4);
memcpy(&m_info.m_uOffset, buf + 16, 4);
memcpy(&uCommentSize, buf + 20, 2);
buf.Release();
m_pStorage->UpdateSpanMode(m_info.m_uThisDisk);
// if m_uThisDisk is not zero, it is enough to say that it is a multi disk archive
ASSERT((!m_info.m_uThisDisk && (m_info.m_uEntriesNumber == m_info.m_uDiskEntriesNo) && !m_info.m_uDiskWithCD) || m_info.m_uThisDisk);
if (!m_pStorage->IsSpanMode() && !m_info.CheckIfOK_1())
ThrowError(CZipException::badZipFile);
if (uCommentSize)
{
m_pszComment.Allocate(uCommentSize);
uRead = m_pStorage->m_pFile->Read(m_pszComment, uCommentSize);
if (uRead != uCommentSize)
ThrowError(CZipException::badZipFile);
}
m_info.SetBytesBeforeZip(m_pStorage->IsSpanMode() != 0);
if (!m_info.CheckIfOK_2())
ThrowError(CZipException::badZipFile);
m_info.m_bOnDisk = true;
m_pStorage->ChangeDisk(m_info.m_uDiskWithCD);
if (!m_info.m_uSize)
return;
ReadHeaders();
}
DWORD CZipCentralDir::Locate()
{
// maximum size of end of central dir record
long uMaxRecordSize = 0xffff + CENTRALDIRSIZE;
DWORD uFileSize = m_pStorage->m_pFile->GetLength();
if ((DWORD)uMaxRecordSize > uFileSize)
uMaxRecordSize = uFileSize;
CZipAutoBuffer buf(m_iBufferSize);
long uPosInFile = 0;
int uRead = 0;
// backward reading
while (uPosInFile < uMaxRecordSize)
{
uPosInFile = uRead + m_iBufferSize;
if (uPosInFile > uMaxRecordSize)
uPosInFile = uMaxRecordSize;
int iToRead = uPosInFile - uRead;
m_pStorage->m_pFile->Seek(-uPosInFile, CZipAbstractFile::end);
int iActuallyRead = m_pStorage->m_pFile->Read(buf, iToRead);
if (iActuallyRead != iToRead)
ThrowError(CZipException::badZipFile);
// search from the very last bytes to prevent an error if inside archive
// there are packed other arhives
for (int i = iToRead - 4; i >=0 ; i--)
if (!memcmp((char*)buf + i, m_gszSignature, 4))
return uFileSize - (uPosInFile - i);
uRead += iToRead - 3;
}
ThrowError(CZipException::cdirNotFound);
return 0;
}
void CZipCentralDir::ThrowError(int err) const
{
CZipException::Throw(err, m_pStorage->m_pFile->GetFilePath());
}
void CZipCentralDir::ReadHeaders()
{
m_pStorage->m_pFile->Seek(m_info.m_uOffset + m_info.m_uBytesBeforeZip, CZipAbstractFile::begin);
RemoveHeaders(); //just in case
for (int i = 0; i < m_info.m_uEntriesNumber; i++)
{
CZipFileHeader* pHeader = new CZipFileHeader;
m_headers.Add(pHeader);
if (!pHeader->Read(m_pStorage))
ThrowError(CZipException::badZipFile);
ConvertFileName(true, true, pHeader);
}
SortHeaders(); // this is necessary when deleting files and removing data descriptors
if (m_bFindFastEnabled)
BuildFindFastArray(m_bCaseSensitive);
}
void CZipCentralDir::SortHeaders()
{
// we cannot use the Sort method of the CZipWordArray,
// because we store pointers (and we need to store pointers
// to make sure that the address of the CZipFileHeader structure
// remains the same while working with the library)
int iSize = m_headers.GetSize();
if (iSize)
qsort((void*)&(m_headers[0]),iSize , sizeof(CZipFileHeader*), CompareHeaders);
}
void CZipCentralDir::Clear(bool bEverything)
{
m_pOpenedFile = NULL;
m_pLocalExtraField.Release();
if (bEverything)
{
RemoveHeaders();
m_findarray.RemoveAll();
m_pszComment.Release();
}
}
bool CZipCentralDir::IsValidIndex(int uIndex)const
{
return uIndex < m_headers.GetSize() && uIndex >= 0;
}
void CZipCentralDir::OpenFile(WORD uIndex)
{
WORD uLocalExtraFieldSize;
m_pOpenedFile = (*this)[uIndex];
m_pStorage->ChangeDisk(m_pOpenedFile->m_uDiskStart);
m_pStorage->m_pFile->Seek(m_pOpenedFile->m_uOffset + m_info.m_uBytesBeforeZip, CZipAbstractFile::begin);
if (!m_pOpenedFile->ReadLocal(m_pStorage, uLocalExtraFieldSize))
ThrowError(CZipException::badZipFile);
m_pLocalExtraField.Release(); // just in case
if (uLocalExtraFieldSize)
{
int iCurrDsk = m_pStorage->GetCurrentDisk();
m_pLocalExtraField.Allocate(uLocalExtraFieldSize);
m_pStorage->Read(m_pLocalExtraField, uLocalExtraFieldSize, true);
if (m_pStorage->GetCurrentDisk() != iCurrDsk)
ThrowError(CZipException::badZipFile);
}
}
void CZipCentralDir::CloseFile(bool bAfterException)
{
if (!m_pOpenedFile)
return;
m_pLocalExtraField.Release();
if (!bAfterException && m_pOpenedFile->IsDataDescr())
{
CZipAutoBuffer buf(12);
m_pStorage->Read(buf, 4, false);
// in span mode, files that are divided between disks have bit 3 of flag set
// which tell about the presence of the data descriptor after the compressed data
// This signature may be in the disk spanning archive that is one volume only
// (it is detected as a non disk spanning archive)
if (memcmp(buf, CZipStorage::m_gszExtHeaderSignat, 4) != 0) // there is no signature
m_pStorage->m_pFile->Seek(-4, CZipAbstractFile::current);
m_pStorage->Read(buf, 12, false);
if (!m_pOpenedFile->CheckCrcAndSizes(buf))
ThrowError(CZipException::badZipFile);
}
m_pOpenedFile = NULL;
}
// add new header using the argument as a template
CZipFileHeader* CZipCentralDir::AddNewFile(const CZipFileHeader & header, int iReplaceIndex)
{
CZipFileHeader* pHeader = new CZipFileHeader(header);
m_pOpenedFile = pHeader;
WORD uIndex;
DWORD uOffset = 0;
bool bReplace = IsValidIndex(iReplaceIndex);
if (bReplace)
{
CZipFileHeader* pfh = m_headers[iReplaceIndex];
uOffset = pfh->m_uOffset + m_info.m_uBytesBeforeZip;
RemoveFile(pfh, iReplaceIndex, false);
m_headers.InsertAt(iReplaceIndex, pHeader);
uIndex = (WORD)iReplaceIndex;
}
else
uIndex = m_headers.Add(pHeader);
if (m_bFindFastEnabled)
InsertFindFastElement(pHeader, uIndex); // GetCount > 0, 'cos we've just added a header
RemoveFromDisk();
if (bReplace)
m_pStorage->m_pFile->Seek(uOffset, CZipAbstractFile::begin);
else
m_pStorage->m_pFile->SeekToEnd();
return pHeader;
}
void CZipCentralDir::RemoveFromDisk()
{
if (m_info.m_bOnDisk)
{
ASSERT(!m_pStorage->IsSpanMode()); // you can't add files to the existing disk span archive or to delete them from it
m_pStorage->m_pFile->SetLength(m_info.m_uBytesBeforeZip + m_info.m_uOffset);
m_info.m_bOnDisk = false;
}
else
m_pStorage->Flush(); // if remove from disk is requested, then the archive modification will follow, so flush the buffers
}
void CZipCentralDir::CloseNewFile()
{
CZipAutoBuffer buf(ZIPARCHIVE_DATADESCRIPTOR_LEN + 4);
short iToWrite = 0;
bool bIsSpan = m_pStorage->IsSpanMode() != 0;
bool bEncrypted = m_pOpenedFile->IsEncrypted();
if (m_pOpenedFile->IsDataDescr())
{
if (bIsSpan || bEncrypted)
{
memcpy(buf, m_pStorage->m_gszExtHeaderSignat, 4);
iToWrite += 4;
}
}
else /*if (!IsSpan)*/
{
ASSERT(!bIsSpan && !bEncrypted);
m_pStorage->Flush();
// the offset contains bytes before zip (set while writting the local header)
m_pStorage->m_pFile->Seek(m_pOpenedFile->m_uOffset + 14, CZipAbstractFile::begin);
// we don't have to restore the pointer, because before adding a new file,
// the pointer is moved to the end
}
m_pOpenedFile->GetCrcAndSizes(buf + iToWrite);
iToWrite += ZIPARCHIVE_DATADESCRIPTOR_LEN;
// offset set during writing the local header
m_pOpenedFile->m_uOffset -= m_info.m_uBytesBeforeZip;
// write the data descriptor and a disk spanning signature at once
m_pStorage->Write(buf, iToWrite, true);
if (!bIsSpan)
{
if (bEncrypted)
{
// write the information to the local header too
m_pStorage->Flush();
m_pStorage->m_pFile->Seek(m_info.m_uBytesBeforeZip + m_pOpenedFile->m_uOffset + 14, CZipAbstractFile::begin);
m_pStorage->Write(buf + 4, ZIPARCHIVE_DATADESCRIPTOR_LEN, true);
}
m_pStorage->Flush();
}
m_pOpenedFile = NULL;
}
void CZipCentralDir::Write(CZipActionCallback* pCallback)
{
if (m_info.m_bOnDisk)
return;
if (!m_pStorage->IsSpanMode())
{
m_pStorage->Flush();
m_pStorage->m_pFile->SeekToEnd();
}
// else
// // we are at the end already
m_info.m_uEntriesNumber = (WORD)m_headers.GetSize();
m_info.m_uSize = 0;
bool bDontAllowDiskChange = false;
// if there is a disk spanning archive in creation and it is only one-volume,
// (current disk is 0 so far, no bytes has been written so we know they are
// all in the buffer) make sure that it will be after writing central dir
// and make it a non disk spanning archive
if (m_pStorage->IsSpanMode() && m_pStorage->GetCurrentDisk() == 0)
{
DWORD uVolumeFree = m_pStorage->VolumeLeft();
// calculate the size of data descriptors already in the buffer or on the disk
// (they will be removed in the non disk spanning archive):
// multi span signature at the beginnig (4 bytes) + the size of the data
// descr. for each file (multi span signature + 12 bytes data)
// the number of bytes to add: central dir size - total to remove;
DWORD uToGrow = GetSize(true) - (4 + m_info.m_uEntriesNumber * (4 + 12));
if (uVolumeFree >= uToGrow)
// lets make sure it will be one-disk archive
{
// can the operation be done only in the buffer?
if (!m_pStorage->m_iBytesWritten && // no bytes on the disk yet
(m_pStorage->GetFreeInBuffer() >= uToGrow)) // is the buffer big enough?
{
RemoveDataDescr(true);
bDontAllowDiskChange = true; // if the disk change occurs somehow, we'll throw an error later
}
else
{
m_pStorage->Flush();
if (RemoveDataDescr(false))
bDontAllowDiskChange = true; // if the disk change occurs somehow, we'll throw an error later
}
}
}
try
{
WriteHeaders(pCallback, bDontAllowDiskChange || !m_pStorage->IsSpanMode());
m_info.m_uThisDisk = (WORD)m_pStorage->GetCurrentDisk();
DWORD uSize = WriteCentralEnd();
if (bDontAllowDiskChange)
{
if (m_pStorage->GetCurrentDisk() != 0)
ThrowError(CZipException::badZipFile);
}
// if after adding a central directory there is a disk change,
// update the information and write it again
if (m_info.m_uThisDisk != m_pStorage->GetCurrentDisk())
{
m_info.DiskChange(m_pStorage->GetCurrentDisk());
if (m_pStorage->m_uBytesInWriteBuffer >= uSize)
// if the data is still in the buffer, simply remove it
m_pStorage->m_uBytesInWriteBuffer -= uSize;
else
{
m_pStorage->Flush();
m_pStorage->m_iBytesWritten -= uSize;
m_pStorage->m_pFile->SeekToBegin();
}
WriteCentralEnd();
}
}
catch (...)
{
if (bDontAllowDiskChange)
{
m_pStorage->FinalizeSpan();
m_info.m_uThisDisk = 0;
}
throw;
}
m_info.m_bOnDisk = true;
}
void CZipCentralDir::WriteHeaders(CZipActionCallback* pCallback, bool bOneDisk)
{
m_info.m_uDiskEntriesNo = 0;
m_info.m_uDiskWithCD = (WORD)m_pStorage->GetCurrentDisk();
m_info.m_uOffset = m_pStorage->GetPosition() - m_info.m_uBytesBeforeZip;
if (!m_info.m_uEntriesNumber)
return;
WORD iDisk = m_info.m_uDiskWithCD;
int iStep = 0; // for the compiler
if (pCallback)
{
pCallback->Init();
pCallback->SetTotal(m_info.m_uEntriesNumber);
iStep = CZipActionCallback::m_iStep;// we don't want to wait forever
}
int iAborted = 0;
for (int i = 0; i < m_info.m_uEntriesNumber; i++)
{
CZipFileHeader* pHeader = (*this)[i];
CZipString szRemember;
if (m_bConvertAfterOpen)
// if CZipArchive::Flush is called we will be still using the archive, so restore changed name
szRemember = pHeader->GetFileName();
ConvertFileName(false, true, pHeader);
m_info.m_uSize += pHeader->Write(m_pStorage);
if (m_bConvertAfterOpen)
pHeader->SetFileName(szRemember);
if (m_pStorage->GetCurrentDisk() != iDisk)
{
m_info.m_uDiskEntriesNo = 1;
iDisk = (WORD)m_pStorage->GetCurrentDisk();
// update the information about the offset and starting disk if the
// first header was written on the new disk
if (i == 0)
{
m_info.m_uOffset = 0;
m_info.m_uDiskWithCD = iDisk;
}
}
else
m_info.m_uDiskEntriesNo++;
if (pCallback && !(i%iStep))
if (!pCallback->Callback(iStep))
{
if (bOneDisk)
{
if (!m_pStorage->IsSpanMode())
m_pStorage->EmptyWriteBuffer();
else
m_pStorage->Flush(); // must be flush before - flush was not called in span mode
// remove saved part from the disk
m_pStorage->m_pFile->SetLength(m_info.m_uBytesBeforeZip + m_info.m_uOffset);
// We can now abort safely
iAborted = CZipException::abortedSafely;
}
else
iAborted = CZipException::abortedAction;
break;
}
}
if (pCallback)
pCallback->CallbackEnd();
if (iAborted)
ThrowError(iAborted);
}
DWORD CZipCentralDir::WriteCentralEnd()
{
DWORD uSize = GetSize();
CZipAutoBuffer buf(uSize);
WORD uCommentSize = (WORD)m_pszComment.GetSize();
memcpy(buf, m_gszSignature, 4);
memcpy(buf + 4, &m_info.m_uThisDisk, 2);
memcpy(buf + 6, &m_info.m_uDiskWithCD, 2);
memcpy(buf + 8, &m_info.m_uDiskEntriesNo, 2);
memcpy(buf + 10, &m_info.m_uEntriesNumber, 2);
memcpy(buf + 12, &m_info.m_uSize, 4);
memcpy(buf + 16, &m_info.m_uOffset, 4);
memcpy(buf + 20, &uCommentSize, 2);
memcpy(buf + 22, m_pszComment, uCommentSize);
m_pStorage->Write(buf, uSize, true);
return uSize;
}
void CZipCentralDir::RemoveAll()
{
m_findarray.RemoveAll();
RemoveHeaders();
}
void CZipCentralDir::RemoveFile(CZipFileHeader* pHeader, int iIndex, bool bShift)
{
if (iIndex == -1)
{
int iCount = m_headers.GetSize();
for (int i = 0; i < iCount; i++)
if (pHeader == m_headers[i])
{
iIndex = i;
break;
}
}
ASSERT(iIndex != -1 || pHeader);
if (!pHeader)
pHeader = m_headers[iIndex];
if (m_bFindFastEnabled)
{
int i = FindFileNameIndex(pHeader->GetFileName());
ASSERT(i != -1);
int uIndex = m_findarray[i].m_uIndex;
m_findarray.RemoveAt(i);
// shift down the indexes
if (bShift)
{
int iSize = m_findarray.GetSize();
for (int j = 0; j < iSize; j++)
{
if (m_findarray[j].m_uIndex > uIndex)
m_findarray[j].m_uIndex--;
}
}
}
if (iIndex != -1)
{
delete pHeader;
m_headers.RemoveAt(iIndex);
}
}
DWORD CZipCentralDir::GetSize(bool bWhole) const
{
DWORD uHeaders = 0;
int iCount = m_headers.GetSize();
if (bWhole)
{
for (int i = 0; i < iCount; i++)
{
const CZipFileHeader* pHeader = m_headers[i];
uHeaders += pHeader->GetSize();
}
}
return CENTRALDIRSIZE + m_pszComment.GetSize() + uHeaders;
}
bool CZipCentralDir::RemoveDataDescr(bool bFromBuffer)
{
ziparchv::CZipFileMapping fm;
char* pFile;
DWORD uSize;
if (bFromBuffer)
{
uSize = m_pStorage->m_uBytesInWriteBuffer;
pFile = m_pStorage->m_pWriteBuffer;
}
else
{
uSize = m_pStorage->m_pFile->GetLength();
// we cannot use CZipMemFile in multidisk archive
// so it MUST be CZipFile
if (!fm.CreateMapping(static_cast<CZipFile*>(m_pStorage->m_pFile)))
return false;
pFile = fm.GetMappedMemory();
}
DWORD uOffsetToChange = 4;
DWORD uPosInBuffer = 0;
DWORD uExtraHeaderLen;
int iCount = m_headers.GetSize();
for (int i = 0; i < iCount; i++)
{
// update the flag value in the local and central header
// int uDataDescr = (m_headers[i]->m_uFlag & 8) ? (4 + 12) : 0;
CZipFileHeader* pHeader = m_headers[i];
char* pSour = pFile + pHeader->m_uOffset;
if (!pHeader->IsEncrypted())
{
// removing data descriptor
pHeader->m_uFlag &= ~8;
// update local header:
// write modified flag in the local header
memcpy(pSour + 6, &pHeader->m_uFlag, 2);
uExtraHeaderLen = 4/*ext. header signature*/ + 12/*data descriptor*/;
}
else
// do not remove data descriptors from encrypted files
uExtraHeaderLen = 0;
// update crc32 and sizes' values
pHeader->GetCrcAndSizes(pSour+ 14);
DWORD uToCopy = (i == (iCount - 1) ? uSize : m_headers[i + 1]->m_uOffset)
- pHeader->m_uOffset - uExtraHeaderLen;
memmove(pFile + uPosInBuffer, pSour, uToCopy);
uPosInBuffer += uToCopy;
pHeader->m_uOffset -= uOffsetToChange;
uOffsetToChange += uExtraHeaderLen;
}
if (bFromBuffer)
m_pStorage->m_uBytesInWriteBuffer = uPosInBuffer;
else
{
m_pStorage->m_iBytesWritten = uPosInBuffer;
fm.RemoveMapping();
m_pStorage->m_pFile->SetLength(uPosInBuffer);
}
return true;
}
void CZipCentralDir::RemoveHeaders()
{
int iCount = m_headers.GetSize();
for (int i = 0; i < iCount; i++)
delete m_headers[i];
m_headers.RemoveAll();
}
void CZipCentralDir::ConvertAll()
{
ASSERT(!m_bConvertAfterOpen);
int iCount = m_headers.GetSize();
for (int i = 0; i < iCount; i++)
ConvertFileName(true, false, m_headers[i]);
m_bConvertAfterOpen = true;
}
void CZipCentralDir::BuildFindFastArray( bool bCaseSensitive )
{
m_findarray.RemoveAll();
m_bCaseSensitive = bCaseSensitive;
m_pCompare = GetCZipStrCompFunc(bCaseSensitive);
int iCount = m_headers.GetSize();
if (!m_bConvertAfterOpen)
{
for (int i = 0; i < iCount; i++)
{
CZipFileHeader fh = *m_headers[i];
ConvertFileName(true, false, &fh);
InsertFindFastElement(&fh, i); // this method requires the name to be already converted
}
}
else
for (int i = 0; i < iCount; i++)
InsertFindFastElement(m_headers[i], i);
}
void CZipCentralDir::EnableFindFast(bool bEnable, bool bCaseSensitive)
{
if (m_bFindFastEnabled == bEnable)
return;
m_bFindFastEnabled = bEnable;
if (bEnable)
BuildFindFastArray(bCaseSensitive);
else
m_findarray.RemoveAll();
}
int CZipCentralDir::FindFile(LPCTSTR lpszFileName, bool bCaseSensitive, bool bSporadically, bool bFileNameOnly)
{
// this is required for fast finding and is done only once
if (!m_bConvertAfterOpen)
{
TRACE(_T("%s(%i) : Converting all the filenames.\n"),__FILE__,__LINE__);
ConvertAll();
}
if (!m_bFindFastEnabled)
EnableFindFast(true, bSporadically ? !bCaseSensitive : bCaseSensitive);
int iResult = -1;
if (bFileNameOnly)
{
// a non-effective search (treat an array as unsorted)
int iSize = m_findarray.GetSize();
for (int i = 0; i < iSize; i++)
{
CZipString sz = GetProperHeaderFileName(m_findarray[i].m_pHeader);
CZipPathComponent::RemoveSeparators(sz); // to find a dir
CZipPathComponent zpc(sz);
sz = zpc.GetFileName();
if ((sz.*m_pCompare)(lpszFileName) == 0)
{
iResult = i;
break;
}
}
}
else if (bCaseSensitive == m_bCaseSensitive)
iResult = FindFileNameIndex(lpszFileName);
else
{
if (bSporadically)
{
// a non-effective search (treat an array as unsorted)
int iSize = m_findarray.GetSize();
for (int i = 0; i < iSize; i++)
if (CompareElement(lpszFileName, (WORD)i) == 0)
{
iResult = i;
break;
}
}
else
{
BuildFindFastArray(bCaseSensitive);
iResult = FindFileNameIndex(lpszFileName);
}
}
return iResult == -1 ? -1 : m_findarray[iResult].m_uIndex;
}
void CZipCentralDir::InsertFindFastElement(CZipFileHeader* pHeader, WORD uIndex)
{
CZipString fileName = pHeader->GetFileName();
int iSize = m_findarray.GetSize();
// Our initial binary search range encompasses the entire array of filenames:
int start = 0;
int end = iSize;
// Keep halving our search range until we find the right place
// to insert the new element:
while ( start < end )
{
// Find the midpoint of the search range:
int midpoint = ( start + end ) / 2;
// Compare the filename with the filename at the midpoint of the current search range:
int result = CompareElement(fileName, (WORD)midpoint);
// If our filename is larger, it must fall in the first half of the search range:
if ( result > 0 )
{
end = midpoint;
}
// If it's smaller, it must fall in the last half:
else if ( result < 0 )
{
start = midpoint + 1;
}
// If they're equal, we can go ahead and insert here:
else
{
start = midpoint; break;
}
}
m_findarray.InsertAt(start, CZipFindFast(pHeader, WORD(uIndex == WORD(-1) ? iSize : uIndex /* just in case */)));
}
int CZipCentralDir::FindFileNameIndex(LPCTSTR lpszFileName) const
{
int start = 0;
int end = m_findarray.GetUpperBound();
// Keep halving our search range until we find the given element:
while ( start <= end )
{
// Find the midpoint of the search range:
int midpoint = ( start + end ) / 2;
// Compare the given filename with the filename at the midpoint of the search range:
int result = CompareElement(lpszFileName, (WORD)midpoint);
// If our filename is smaller, it must fall in the first half of the search range:
if ( result > 0 )
{
end = midpoint - 1;
}
// If it's larger, it must fall in the last half:
else if ( result < 0 )
{
start = midpoint + 1;
}
// If they're equal, return the result:
else
{
return midpoint;
}
}
// Signal failure:
return -1;
}
void CZipCentralDir::RenameFile(WORD uIndex, LPCTSTR lpszNewName)
{
CZipFileHeader* pHeader = m_headers[uIndex];
pHeader->SetFileName(lpszNewName);
if (!m_bConvertAfterOpen)
ZipCompatibility::FileNameUpdate(*pHeader, false);
if (m_bFindFastEnabled)
BuildFindFastArray(m_bCaseSensitive);
}

View File

@@ -0,0 +1,214 @@
////////////////////////////////////////////////////////////////////////////////
// $Workfile: ZipCompatibility.cpp $
// $Archive: /ZipArchive/ZipCompatibility.cpp $
// $Date$ $Author$
////////////////////////////////////////////////////////////////////////////////
// This source file is part of the ZipArchive library source distribution and
// is Copyright 2000-2003 by Tadeusz Dracz (http://www.artpol-software.com/)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// For the licensing details see the file License.txt
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "zipcompatibility.h"
#include "zipplatform.h"
#include "zipexception.h"
#include "zipautobuffer.h"
#include "zipfileheader.h"
enum iInternalAttr
{
attROnly = 0x01,
attHidd = 0x02,
attSys = 0x04,
attDir = 0x10,
attArch = 0x20
};
// *********************** WINDOWS **************************
#ifndef _WIN32
#define FILE_ATTRIBUTE_READONLY 0x00000001
#define FILE_ATTRIBUTE_HIDDEN 0x00000002
#define FILE_ATTRIBUTE_SYSTEM 0x00000004
#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
#define FILE_ATTRIBUTE_ARCHIVE 0x00000020
#endif
// *********************** UINX **************************
#define USER_PERMISSIONS_MASK 0x01C00000
#define EXTRACT_USER_PERMISSIONS(x) ((x & USER_PERMISSIONS_MASK) >> 22)
#define CREATE_USER_PERMISSIONS(x) ((x & 0x0007) << 22)
#define GROUP_PERMISSIONS_MASK 0x00380000
#define EXTRACT_GROUP_PERMISSIONS ((x & GROUP_PERMISSIONS_MASK) >> 19)
#define CREATE_GROUP_PERMISSIONS(x) ((x & 0x0007) << 19)
#define OTHER_PERMISSIONS_MASK 0x00070000
#define EXTRACT_OTHER_PERMISSIONS ((x & OTHER_PERMISSIONS_MASK) >> 16)
#define CREATE_OTHER_PERMISSIONS(x) ((x & 0x0007) << 16)
#define UNIX_DIRECTORY_ATTRIBUTE 0x40000000
#define UNIX_FILE_ATTRIBUTE 0x80000000
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
using namespace ZipCompatibility;
typedef DWORD(*conv_func)(DWORD , bool );
DWORD AttrDos(DWORD , bool );
DWORD AttrUnix(DWORD, bool);
DWORD AttrMac(DWORD , bool );
// more to come...
conv_func conv_funcs[11] = {AttrDos,
NULL,
NULL,
AttrUnix,
NULL,
NULL,
AttrDos,
AttrMac,
NULL,
NULL,
AttrDos
};
DWORD ZipCompatibility::ConvertToSystem(DWORD uAttr, int iFromSystem, int iToSystem)
{
if (iToSystem != iFromSystem && iFromSystem < 11 && iToSystem < 11)
{
conv_func p = conv_funcs[iFromSystem], q = conv_funcs[iToSystem];
if (p && q)
uAttr = q( p(uAttr, true), false);
else
CZipException::Throw(CZipException::platfNotSupp);
}
return uAttr;
}
DWORD AttrDos(DWORD uAttr, bool )
{
return uAttr;
}
DWORD AttrUnix(DWORD uAttr, bool bFrom)
{
DWORD uNewAttr = 0;
if (bFrom)
{
if (uAttr & UNIX_DIRECTORY_ATTRIBUTE)
uNewAttr = attDir;
uAttr = EXTRACT_USER_PERMISSIONS (uAttr);
// we may set archive attribute if the file hasn't the execute permissions
//
if (!(uAttr & 1))
uNewAttr |= attArch ;
if (!(uAttr & 2))
uNewAttr |= attROnly;
if (!(uAttr & 4))
uNewAttr |= attHidd;
}
else
{
uNewAttr = 0; // we cannot assume that if the file hasn't the archive attribute set
//then it is executable and set execute permissions
if (!(uAttr & attHidd))
uNewAttr |= (CREATE_OTHER_PERMISSIONS (4) |
CREATE_GROUP_PERMISSIONS (4))
| CREATE_USER_PERMISSIONS (4);
if (!(uAttr & attROnly))
uNewAttr |= (CREATE_GROUP_PERMISSIONS (2) |
CREATE_USER_PERMISSIONS (2));
if (uAttr & attDir)
uNewAttr |= UNIX_DIRECTORY_ATTRIBUTE | attDir;
else
uNewAttr |= UNIX_FILE_ATTRIBUTE;
}
return uNewAttr;
}
DWORD AttrMac(DWORD uAttr, bool )
{
DWORD uNewAttr = uAttr & (attDir | attROnly);
// if (bFrom)
// {
//
// }
// else
// {
//
// }
return uNewAttr;
}
// ************************************************************************
ZIPINLINE bool ZipCompatibility::IsPlatformSupported(int iCode)
{
return iCode == zcDosFat || iCode == zcUnix || iCode == zcMacintosh
|| iCode == zcNtfs || iCode == zcOs2Hpfs;
}
void ZipCompatibility::FileNameUpdate(CZipFileHeader& header, bool bFromZip)
{
int iSysHeader = header.GetSystemCompatibility();
int iCurSystem = ZipPlatform::GetSystemID();
if (bFromZip)
{
if (iCurSystem == zcDosFat)
SlashBackslashChg(header.m_pszFileName, true);
if (iSysHeader == zcDosFat)
ZipPlatform::AnsiOem(header.m_pszFileName, false);
}
else
{
if (iSysHeader == zcDosFat)
{
ZipPlatform::AnsiOem(header.m_pszFileName, true);
}
SlashBackslashChg(header.m_pszFileName, false);
}
}
void ZipCompatibility::SlashBackslashChg(CZipAutoBuffer& buffer, bool bReplaceSlash)
{
char t1 = '\\' /*backslash*/, t2 = '/', c1, c2;
if (bReplaceSlash)
{
c1 = t1;
c2 = t2;
}
else
{
c1 = t2;
c2 = t1;
}
for (DWORD i = 0; i < buffer.GetSize(); i++)
{
if (buffer[i] == c2)
buffer[i] = c1;
}
}

View File

@@ -0,0 +1,280 @@
////////////////////////////////////////////////////////////////////////////////
// $Workfile: ZipException.cpp $
// $Archive: /ZipArchive/ZipException.cpp $
// $Date$ $Author$
////////////////////////////////////////////////////////////////////////////////
// This source file is part of the ZipArchive library source distribution and
// is Copyright 2000-2003 by Tadeusz Dracz (http://www.artpol-software.com/)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// For the licensing details see the file License.txt
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "zipexception.h"
#include <errno.h>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#ifdef _MFC_VER
IMPLEMENT_DYNAMIC( CZipException, CException)
#endif
CZipException::CZipException(int iCause, LPCTSTR lpszZipName)
#ifdef _MFC_VER
:CException(TRUE)
#endif
{
m_iCause = iCause;
if (lpszZipName)
m_szFileName = lpszZipName;
}
//CZipException::~CZipException()
#if __GNUC__ >=3
CZipException::~CZipException() throw()
#else
CZipException::~CZipException()
#endif
{
}
// inline void CZipException::Throw(int iZipError, LPCTSTR lpszZipName)
// {
// #ifdef _MFC_VER
// throw new CZipException(iZipError, lpszZipName);
// #else
// CZipException e(iZipError, lpszZipName);
// throw e;
// #endif
// MSVC++: ignore "Unreachable code" warning here, it's due to
// optimizations
// }
int CZipException::ZlibErrToZip(int iZlibError)
{
switch (iZlibError)
{
case 2://Z_NEED_DICT:
return CZipException::needDict;
case 1://Z_STREAM_END:
return CZipException::streamEnd;
case -1://Z_ERRNO:
return CZipException::errNo;
case -2://Z_STREAM_ERROR:
return CZipException::streamError;
case -3://Z_DATA_ERROR:
return CZipException::dataError;
case -4://Z_MEM_ERROR:
return CZipException::memError;
case -5://Z_BUF_ERROR:
return CZipException::bufError;
case -6://Z_VERSION_ERROR:
return CZipException::versionError;
default:
return CZipException::generic;
}
}
#ifdef ZIP_ENABLE_ERROR_DESCRIPTION
BOOL CZipException::GetErrorMessage(LPTSTR lpszError, UINT nMaxError,
UINT* )
{
if (!lpszError || !nMaxError)
return FALSE;
CZipString sz = GetErrorDescription();
if (sz.IsEmpty())
return FALSE;
UINT iLen = sz.GetLength();
if (nMaxError - 1 < iLen)
iLen = nMaxError - 1;
LPTSTR lpsz = sz.GetBuffer(iLen);
#ifdef _UNICODE
wcsncpy(lpszError, lpsz, iLen);
#else
strncpy(lpszError, lpsz, iLen);
#endif
lpszError[iLen] = _T('\0');
return TRUE;
}
CZipString CZipException::GetErrorDescription()
{
return GetInternalErrorDescription(m_iCause);
}
CZipString CZipException::GetSystemErrorDescription()
{
#ifdef WIN32
DWORD x = GetLastError();
if (x)
{
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, x, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf, 0, NULL);
CZipString sz = (LPCTSTR)lpMsgBuf;
LocalFree(lpMsgBuf);
return sz;
}
#endif
return GetInternalErrorDescription(errno == 0 ? generic : errno, true);
}
CZipString CZipException::GetInternalErrorDescription(int iCause, bool bNoLoop)
{
CZipString sz;
switch (iCause)
{
case EROFS:
sz = _T("Read-only file system");
break;
case ESPIPE:
sz = _T("Illegal seek");
break;
case ENOSPC:
sz = _T("No space left on device");
break;
case EFBIG:
sz = _T("File too large");
break;
case EMFILE:
sz = _T("Too many open files");
break;
case ENFILE:
sz = _T("File table overflow");
break;
case EINVAL:
sz = _T("Invalid argument");
break;
case EISDIR:
sz = _T("Is a directory");
break;
case ENOTDIR:
sz = _T("Not a directory");
break;
case ENODEV:
sz = _T("No such device");
break;
case EXDEV:
sz = _T("Cross-device link");
break;
case EEXIST:
sz = _T("File exists");
break;
case EFAULT:
sz = _T("Bad address");
break;
case EACCES:
sz = _T("Permission denied");
break;
case ENOMEM:
sz = _T("Not enough space");
break;
case EBADF:
sz = _T("Bad file number");
break;
case ENXIO:
sz = _T("No such device or address");
break;
case EIO:
sz = _T("I/O error");
break;
case EINTR:
sz = _T("Interrupted system call");
break;
case ENOENT:
sz = _T("No such file or directory");
break;
case EPERM:
sz = _T("Not super-user");
break;
case badZipFile:
sz = _T("Damaged or not a zip file");
break;
case badCrc:
sz = _T("Crc mismatched");
break;
case noCallback:
sz = _T("No disk-spanning callback functor set");
break;
case aborted:
sz = _T("Disk change aborted");
break;
case abortedAction:
sz = _T("Action aborted");
break;
case abortedSafely:
sz = _T("Action aborted safely");
break;
case nonRemovable:
sz = _T("The device selected for the disk spanning archive is non removable");
break;
case tooManyVolumes:
sz = _T("Limit of the maximum volumes reached (999)");
break;
case tooLongFileName:
sz = _T("The filename of the file being added to the archive is too long");
break;
case badPassword:
sz = _T("Incorrect password set for the file being decrypted");
break;
case dirWithSize:
sz = _T("During testing found the directory with the size greater than 0");
break;
case internal:
sz = _T("Internal error");
break;
case notRemoved:
sz.Format(_T("%s (%s)"), _T("Error while removing a file"), (LPCTSTR)GetSystemErrorDescription());
break;
case notRenamed:
sz.Format(_T("%s (%s)"), _T("Error while renaming a file"), (LPCTSTR)GetSystemErrorDescription());
break;
case platfNotSupp:
sz = _T("Cannot create the file for the specified platform");
break;
case cdirNotFound:
sz = _T("The central directory was not found in the archive (or you were trying to open not the last disk of a multi-disk archive)");
break;
case streamEnd:
sz = _T("Zlib Library error (end of stream)");
break;
case errNo:
sz = GetInternalErrorDescription(errno != errNo ? errno : generic);
break;
case streamError:
sz = _T("Zlib library error (stream error)");
break;
case dataError:
sz = _T("Zlib library error (data error)");
break;
case memError:
sz = _T("Not enough memory");
break;
case bufError:
sz = _T("Zlib library error (buffer error)");
break;
case versionError:
sz = _T("Zlib library error (version error)");
break;
default:
sz = bNoLoop ? _T("Unknown error") :(LPCTSTR) GetSystemErrorDescription();
}
return sz;
}
#endif //ZIP_ENABLE_ERROR_DESCRIPTION

View File

@@ -0,0 +1,114 @@
////////////////////////////////////////////////////////////////////////////////
// $Workfile: ZipFile.cpp $
// $Archive: /ZipArchive_STL/ZipFile.cpp $
// $Date$ $Author$
////////////////////////////////////////////////////////////////////////////////
// This source file is part of the ZipArchive library source distribution and
// is Copyright 2000-2003 by Tadeusz Dracz (http://www.artpol-software.com/)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// For the licensing details see the file License.txt
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "zipfile.h"
#include "zipexception.h"
#include "zipplatform.h"
#include <fcntl.h>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CZipFile::CZipFile()
{
m_hFile = -1;
}
void CZipFile::ThrowError() const
{
CZipException::Throw(errno, m_szFileName);
}
ZIP_ULONGLONG CZipFile::GetLength() const
{
// cannot use Seek here, Seek is not const
long lLen, lCur;
lCur = lseek(m_hFile, 0, current);
if (lCur == -1)
ThrowError();
lLen = lseek(m_hFile, 0, end);
// first get back
lseek(m_hFile, lCur, begin);
if (lLen == -1)
ThrowError();
return lLen;
}
bool CZipFile::Open(LPCTSTR lpszFileName, UINT openFlags, bool bThrow)
{
if (!IsClosed())
Close();
#ifndef __GNUC__
UINT iNewFlags = O_BINARY;
#else
UINT iNewFlags = 0;
#endif
bool bReadOnly = false;
if (openFlags & CZipFile::modeCreate)
iNewFlags |= O_CREAT;
if ((openFlags & CZipFile::modeReadWrite) == CZipFile::modeReadWrite)
iNewFlags |= O_RDWR;
else if (openFlags & CZipFile::modeRead)
{
// O_RDONLY is defined as 0
bReadOnly = true;
iNewFlags |= O_RDONLY;
}
else if (openFlags & CZipFile::modeWrite)
iNewFlags |= O_WRONLY;
if (!(openFlags & CZipFile::modeNoTruncate) && !bReadOnly)
iNewFlags |= O_TRUNC;
m_hFile = ZipPlatform::OpenFile(lpszFileName, iNewFlags, openFlags & 0x1C);
if (m_hFile == -1)
if (bThrow)
ThrowError();
else
return false;
m_szFileName = lpszFileName;
return true;
}
void CZipFile::SetLength(ZIP_ULONGLONG nNewLen)
{
ZipPlatform::TruncateFile(m_hFile, (DWORD)nNewLen);
}
void CZipFile::Flush()
{
if (!ZipPlatform::FlushFile(m_hFile))
ThrowError();
}
CZipFile::operator HANDLE()
{
int fh = ZipPlatform::GetFileSystemHandle(m_hFile);
if (fh == -1)
ThrowError();
return (HANDLE)fh;
}

View File

@@ -0,0 +1,340 @@
////////////////////////////////////////////////////////////////////////////////
// $Workfile: ZipFileHeader.cpp $
// $Archive: /ZipArchive_STL/ZipFileHeader.cpp $
// $Date$ $Author$
////////////////////////////////////////////////////////////////////////////////
// This source file is part of the ZipArchive library source distribution and
// is Copyright 2000-2003 by Tadeusz Dracz (http://www.artpol-software.com/)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// For the licensing details see the file License.txt
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "zipfileheader.h"
#include "zipautobuffer.h"
#include "ziparchive.h"
#include "zipplatform.h"
#include "zipcompatibility.h"
#include <time.h>
#define FILEHEADERSIZE 46
#define LOCALFILEHEADERSIZE 30
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
char CZipFileHeader::m_gszSignature[] = {0x50, 0x4b, 0x01, 0x02};
char CZipFileHeader::m_gszLocalSignature[] = {0x50, 0x4b, 0x03, 0x04};
CZipFileHeader::CZipFileHeader()
{
m_uExternalAttr = 0;//ZipPlatform::GetDefaultAttributes();
m_uModDate = m_uModTime = 0;
m_uMethod = Z_DEFLATED;
// SetSystemCompatibility(ZipPlatform::m_sSystemID);
}
CZipFileHeader::~CZipFileHeader()
{
}
// read the header from the central dir
bool CZipFileHeader::Read(CZipStorage *pStorage)
{
// // just in case
// m_pszComment.Release();
// m_pszFileName.Release();
WORD uFileNameSize, uCommentSize, uExtraFieldSize;
CZipAutoBuffer buf(FILEHEADERSIZE);
pStorage->Read(buf, FILEHEADERSIZE, true);
memcpy(&m_szSignature, buf, 4);
memcpy(&m_uVersionMadeBy, buf + 4, 2);
memcpy(&m_uVersionNeeded, buf + 6, 2);
memcpy(&m_uFlag, buf + 8, 2);
memcpy(&m_uMethod, buf + 10, 2);
memcpy(&m_uModTime, buf + 12, 2);
memcpy(&m_uModDate, buf + 14, 2);
memcpy(&m_uCrc32, buf + 16, 4);
memcpy(&m_uComprSize, buf + 20, 4);
memcpy(&m_uUncomprSize, buf + 24, 4);
memcpy(&uFileNameSize, buf + 28, 2);
memcpy(&uExtraFieldSize, buf + 30, 2);
memcpy(&uCommentSize, buf + 32, 2);
memcpy(&m_uDiskStart, buf + 34, 2);
memcpy(&m_uInternalAttr, buf + 36, 2);
memcpy(&m_uExternalAttr, buf + 38, 4);
memcpy(&m_uOffset, buf + 42, 4);
buf.Release();
if (memcmp(m_szSignature, m_gszSignature, 4) != 0)
return false;
int iCurDsk = pStorage->GetCurrentDisk();
m_pszFileName.Allocate(uFileNameSize); // don't add NULL at the end
pStorage->Read(m_pszFileName, uFileNameSize, true);
if (uExtraFieldSize)
{
ASSERT(!m_pExtraField.IsAllocated());
m_pExtraField.Allocate(uExtraFieldSize);
pStorage->Read(m_pExtraField, uExtraFieldSize, true);
}
if (uCommentSize)
{
m_pszComment.Allocate(uCommentSize);
pStorage->Read(m_pszComment, uCommentSize, true);
}
return pStorage->GetCurrentDisk() == iCurDsk; // check that the whole header is on the one disk
}
time_t CZipFileHeader::GetTime()const
{
struct tm atm;
atm.tm_sec = (m_uModTime & ~0xFFE0) << 1;
atm.tm_min = (m_uModTime & ~0xF800) >> 5;
atm.tm_hour = m_uModTime >> 11;
atm.tm_mday = m_uModDate & ~0xFFE0;
atm.tm_mon = ((m_uModDate & ~0xFE00) >> 5) - 1;
atm.tm_year = (m_uModDate >> 9) + 80;
atm.tm_isdst = -1;
return mktime(&atm);
}
// write the header to the central dir
DWORD CZipFileHeader::Write(CZipStorage *pStorage)
{
WORD uFileNameSize = GetFileNameSize(), uCommentSize = GetCommentSize(),
uExtraFieldSize = GetExtraFieldSize();
DWORD iSize = FILEHEADERSIZE + uFileNameSize + uCommentSize + uExtraFieldSize;
CZipAutoBuffer buf(iSize);
memcpy(buf, &m_szSignature, 4);
memcpy(buf + 4, &m_uVersionMadeBy, 2);
memcpy(buf + 6, &m_uVersionNeeded, 2);
memcpy(buf + 8, &m_uFlag, 2);
memcpy(buf + 10, &m_uMethod, 2);
memcpy(buf + 12, &m_uModTime, 2);
memcpy(buf + 14, &m_uModDate, 2);
memcpy(buf + 16, &m_uCrc32, 4);
memcpy(buf + 20, &m_uComprSize, 4);
memcpy(buf + 24, &m_uUncomprSize, 4);
memcpy(buf + 28, &uFileNameSize, 2);
memcpy(buf + 30, &uExtraFieldSize, 2);
memcpy(buf + 32, &uCommentSize, 2);
memcpy(buf + 34, &m_uDiskStart, 2);
memcpy(buf + 36, &m_uInternalAttr, 2);
memcpy(buf + 38, &m_uExternalAttr, 4);
memcpy(buf + 42, &m_uOffset, 4);
memcpy(buf + 46, m_pszFileName, uFileNameSize);
if (uExtraFieldSize)
memcpy(buf + 46 + uFileNameSize, m_pExtraField, uExtraFieldSize);
if (uCommentSize)
memcpy(buf + 46 + uFileNameSize + uExtraFieldSize, m_pszComment, uCommentSize);
pStorage->Write(buf, iSize, true);
return iSize;
}
bool CZipFileHeader::ReadLocal(CZipStorage *pStorage, WORD& iLocExtrFieldSize)
{
char buf[LOCALFILEHEADERSIZE];
pStorage->Read(buf, LOCALFILEHEADERSIZE, true);
if (memcmp(buf, m_gszLocalSignature, 4) != 0)
return false;
bool bIsDataDescr = (((WORD)*(buf + 6)) & 8) != 0;
WORD uFileNameSize = GetFileNameSize();
WORD uTemp;
memcpy(&uTemp, buf+6, 2); // give the priority to the local flag
if ((uTemp & 0xf) != (m_uFlag & 0xf))
m_uFlag = uTemp;
if ((memcmp(buf + 8, &m_uMethod, 2) != 0)
|| (m_uMethod && (m_uMethod != Z_DEFLATED))
|| (memcmp(buf + 26, &uFileNameSize, 2) != 0))
return false;
// jeszcze mo¿naby porównaæ nazwy plików
if (!bIsDataDescr/* || !pStorage->IsSpanMode()*/)
if (!CheckCrcAndSizes(buf + 14))
return false;
memcpy(&iLocExtrFieldSize, buf + 28, 2);
pStorage->m_pFile->Seek(uFileNameSize, CZipAbstractFile::current);
return true;
}
void CZipFileHeader::SetTime(const time_t & ttime)
{
tm* gt = localtime(&ttime);
WORD year = (WORD)(gt->tm_year + 1900);
if (year <= 1980)
year = 0;
else
year -= 1980;
m_uModDate = (WORD) (gt->tm_mday + ((gt->tm_mon + 1)<< 5) + (year << 9));
m_uModTime = (WORD) ((gt->tm_sec >> 1) + (gt->tm_min << 5) +
(gt->tm_hour << 11));
}
// the buffer contains crc32, compressed and uncompressed sizes to be compared
// with the actual values
bool CZipFileHeader::CheckCrcAndSizes(char *pBuf) const
{
return (memcmp(pBuf, &m_uCrc32, 4) == 0) && (memcmp(pBuf + 4, &m_uComprSize, 4) == 0)
&& (memcmp(pBuf + 8, &m_uUncomprSize, 4) == 0);
}
// write the local header
void CZipFileHeader::WriteLocal(CZipStorage& storage)
{
// extra field is local by now
WORD uFileNameSize = GetFileNameSize(), uExtraFieldSize = GetExtraFieldSize();
DWORD iLocalSize = LOCALFILEHEADERSIZE + uExtraFieldSize + uFileNameSize;
CZipAutoBuffer buf(iLocalSize);
memcpy(buf, m_gszLocalSignature, 4);
memcpy(buf + 4, &m_uVersionNeeded, 2);
memcpy(buf + 6, &m_uFlag, 2);
memcpy(buf + 8, &m_uMethod, 2);
memcpy(buf + 10, &m_uModTime, 2);
memcpy(buf + 12, &m_uModDate, 2);
memcpy(buf + 14, &m_uCrc32, 4);
memcpy(buf + 18, &m_uComprSize, 4);
memcpy(buf + 22, &m_uUncomprSize, 4);
memcpy(buf + 26, &uFileNameSize, 2);
memcpy(buf + 28, &uExtraFieldSize, 2);
memcpy(buf + 30, m_pszFileName, uFileNameSize);
memcpy(buf + 30 + uFileNameSize, m_pExtraField, uExtraFieldSize);
// possible disk change before writing to the file in the disk spanning mode
// so write the local header first
storage.Write(buf, iLocalSize, true);
// it was only local information, use CZipArchive::SetExtraField to set the file extra field in the central directory
m_pExtraField.Release();
m_uDiskStart = (WORD)storage.GetCurrentDisk();
m_uOffset = storage.GetPosition() - iLocalSize;
}
// prepare the data before adding a new file
bool CZipFileHeader::PrepareData(int iLevel, bool bSpan, bool bEncrypted)
{
memcpy(m_szSignature, m_gszSignature, 4);
m_uInternalAttr = 0;
m_uVersionNeeded = IsDirectory() ? 0xa : 0x14; // 1.0 or 2.0
SetVersion((WORD)(0x14));
m_uCrc32 = 0;
m_uComprSize = 0;
m_uUncomprSize = 0;
if (iLevel == 0)
m_uMethod = 0;
if ((m_uMethod != Z_DEFLATED) && (m_uMethod != 0))
m_uMethod = Z_DEFLATED;
m_uFlag = 0;
if (m_uMethod == Z_DEFLATED)
switch (iLevel)
{
case 1:
m_uFlag |= 6;
break;
case 2:
m_uFlag |= 4;
break;
case 8:
case 9:
m_uFlag |= 2;
break;
}
if (bSpan || bEncrypted)
m_uFlag |= 8; // data descriptor present
if (bEncrypted)
{
m_uComprSize = ZIPARCHIVE_ENCR_HEADER_LEN; // encrypted header
m_uFlag |= 1; // encrypted file
}
return !(m_pszComment.GetSize() > USHRT_MAX || m_pszFileName.GetSize() > USHRT_MAX
|| m_pExtraField.GetSize() > USHRT_MAX);
}
void CZipFileHeader::GetCrcAndSizes(char * pBuffer)const
{
memcpy(pBuffer, &m_uCrc32, 4);
memcpy(pBuffer + 4, &m_uComprSize, 4);
memcpy(pBuffer + 8, &m_uUncomprSize, 4);
}
DWORD CZipFileHeader::GetSize(bool bLocal)const
{
if (bLocal)
return LOCALFILEHEADERSIZE + GetExtraFieldSize() + GetFileNameSize();
else
return FILEHEADERSIZE + GetExtraFieldSize() + GetFileNameSize() + GetCommentSize();
}
bool CZipFileHeader::SetComment(LPCTSTR lpszComment)
{
return CZipArchive::WideToSingle(lpszComment, m_pszComment) != -1;
}
CZipString CZipFileHeader::GetComment() const
{
CZipString temp;
CZipArchive::SingleToWide(m_pszComment, temp);
return temp;
}
bool CZipFileHeader::SetFileName(LPCTSTR lpszFileName)
{
return CZipArchive::WideToSingle(lpszFileName, m_pszFileName) != -1;
}
CZipString CZipFileHeader::GetFileName()const
{
CZipString temp;
CZipArchive::SingleToWide(m_pszFileName, temp);
return temp;
}
bool CZipFileHeader::IsDirectory()const
{
return ZipPlatform::IsDirectory(GetSystemAttr());
}
DWORD CZipFileHeader::GetSystemAttr()const
{
int iSystemComp = GetSystemCompatibility();
if (ZipCompatibility::IsPlatformSupported(iSystemComp))
{
if (!m_uExternalAttr && CZipPathComponent::HasEndingSeparator(GetFileName()))
return ZipPlatform::GetDefaultDirAttributes(); // can happen
else
return ZipCompatibility::ConvertToSystem(m_uExternalAttr, iSystemComp, ZipPlatform::GetSystemID());
}
else
return CZipPathComponent::HasEndingSeparator(GetFileName()) ? ZipPlatform::GetDefaultDirAttributes() : ZipPlatform::GetDefaultAttributes();
}
void CZipFileHeader::SetSystemAttr(DWORD uAttr)
{
m_uExternalAttr = ZipCompatibility::ConvertToSystem(uAttr, ZipPlatform::GetSystemID(), GetSystemCompatibility());
}

View File

@@ -0,0 +1,98 @@
////////////////////////////////////////////////////////////////////////////////
// $Workfile: ZipMemFile.cpp $
// $Archive: /ZipArchive/ZipMemFile.cpp $
// $Date$ $Author$
////////////////////////////////////////////////////////////////////////////////
// This source file is part of the ZipArchive library source distribution and
// is Copyright 2000-2003 by Tadeusz Dracz (http://www.artpol-software.com/)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// For the licensing details see the file License.txt
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "zipmemfile.h"
#include "zipexception.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
void CZipMemFile::Grow(size_t nGrowTo)
{
if (m_nBufSize < (UINT)nGrowTo)
{
if (m_nGrowBy == 0)
CZipException::Throw(CZipException::memError);
size_t nNewSize = m_nBufSize;
while (nNewSize < nGrowTo)
nNewSize += m_nGrowBy;
BYTE* lpNew;
if (m_lpBuf)
lpNew = (BYTE*)hb_xrealloc((void*) m_lpBuf, nNewSize);
else
lpNew = (BYTE*)hb_xalloc(nNewSize);
if (!lpNew)
CZipException::Throw(CZipException::memError);
m_nBufSize = nNewSize;
m_lpBuf = lpNew;
}
}
void CZipMemFile::SetLength(ZIP_ULONGLONG nNewLen)
{
if (m_nBufSize < (UINT)nNewLen)
Grow((size_t)nNewLen);
else
m_nPos = (size_t)nNewLen;
m_nDataSize = (size_t)nNewLen;
}
UINT CZipMemFile::Read(void *lpBuf, UINT nCount)
{
if (m_nPos > m_nDataSize)
return 0;
UINT nToRead = (m_nPos + nCount > m_nDataSize) ? m_nDataSize - m_nPos : nCount;
memcpy(lpBuf, m_lpBuf + m_nPos, nToRead);
m_nPos += nToRead;
return nToRead;
}
void CZipMemFile::Write(const void *lpBuf, UINT nCount)
{
if (!nCount)
return;
if (m_nPos + nCount > m_nBufSize)
Grow(m_nPos + nCount);
memcpy(m_lpBuf + m_nPos, lpBuf, nCount);
m_nPos += nCount;
if (m_nPos > m_nDataSize)
m_nDataSize = m_nPos;
}
ZIP_ULONGLONG CZipMemFile::Seek(ZIP_LONGLONG lOff, int nFrom)
{
ZIP_ULONGLONG lNew = m_nPos;
if (nFrom == CZipAbstractFile::begin)
lNew = lOff;
else if (nFrom == CZipAbstractFile::current)
lNew += lOff;
else if (nFrom == CZipAbstractFile::end)
lNew = m_nDataSize + lOff;
else
return lNew;
if (lNew< 0)
CZipException::Throw(CZipException::memError);
m_nPos = (size_t)lNew;
return lNew;
}

View File

@@ -0,0 +1,76 @@
////////////////////////////////////////////////////////////////////////////////
// $Workfile: ZipPathComponent.cpp $
// $Archive: /ZipArchive/ZipPathComponent.cpp $
// $Date$ $Author$
////////////////////////////////////////////////////////////////////////////////
// This source file is part of the ZipArchive library source distribution and
// is Copyright 2000-2003 by Tadeusz Dracz (http://www.artpol-software.com/)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// For the licensing details see the file License.txt
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "zippathcomponent.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CZipPathComponent::~CZipPathComponent()
{
}
void CZipPathComponent::SetFullPath(LPCTSTR lpszFullPath)
{
TCHAR szDrive[_MAX_DRIVE];
TCHAR szDir[_MAX_DIR];
TCHAR szFname[_MAX_FNAME];
TCHAR szExt[_MAX_EXT];
CZipString szTempPath(lpszFullPath);
const CZipString szPrefix = _T("\\\\?\\unc\\");
int i = -1, iLen = szPrefix.GetLength();
if (iLen > szTempPath.GetLength())
iLen = szTempPath.GetLength();
CZipString szPossiblePrefix = szTempPath.Left(iLen);
szPossiblePrefix.MakeLower(); // must perform case insensitive comparison
while (++i < iLen && szPossiblePrefix[i] == szPrefix[i]);
if (i == 2 || i == 4 || i == 8) // unc path, unicode path or unc path meeting windows file name conventions
{
m_szPrefix = szTempPath.Left(i);
szTempPath = szTempPath.Mid(i);
}
else
m_szPrefix.Empty();
_tsplitpath(szTempPath, szDrive , szDir, szFname, szExt);
m_szDrive = szDrive;
m_szDirectory = szDir;
m_szDirectory.TrimLeft(m_cSeparator);
m_szDirectory.TrimRight(m_cSeparator);
SetExtension(szExt);
m_szFileTitle = szFname;
}
CZipString CZipPathComponent::GetNoDrive() const
{
CZipString szPath = m_szDirectory;
CZipString szFileName = GetFileName();
if (!szFileName.IsEmpty() && !szPath.IsEmpty())
szPath += m_cSeparator;
szPath += szFileName;
return szPath;
}

View File

@@ -0,0 +1,351 @@
////////////////////////////////////////////////////////////////////////////////
// $Workfile: ZipPlatform.cpp $
// $Archive: /ZipArchive/ZipPlatform.cpp $
// $Date$ $Author$
////////////////////////////////////////////////////////////////////////////////
// This source file is part of the ZipArchive library source distribution and
// is Copyright 2000-2003 by Tadeusz Dracz (http://www.artpol-software.com/)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// For the licensing details see the file License.txt
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "zipplatform.h"
#include "zipfileheader.h"
#include "zipexception.h"
#include "zipautobuffer.h"
#include <sys/stat.h>
#if defined _MSC_VER && !defined __BORLANDC__ /*_MSC_VER may be defined in Borland after converting the VC project */
#include <sys/utime.h>
#else
#include <utime.h>
#endif
#include <direct.h>
#include <io.h>
#include <time.h>
#include "zippathcomponent.h"
#include "zipcompatibility.h"
const TCHAR CZipPathComponent::m_cSeparator = _T('\\');
#ifndef _UTIMBUF_DEFINED
#define _utimbuf utimbuf
#endif
DWORD ZipPlatform::GetDeviceFreeSpace(LPCTSTR lpszPath)
{
DWORD SectorsPerCluster, BytesPerSector, NumberOfFreeClusters, TotalNumberOfClusters;
CZipPathComponent zpc (lpszPath);
CZipString szDrive = zpc.GetFileDrive();
if (!GetDiskFreeSpace(
szDrive,
&SectorsPerCluster,
&BytesPerSector,
&NumberOfFreeClusters,
&TotalNumberOfClusters))
{
CZipPathComponent::AppendSeparator(szDrive); // in spite of what is written in MSDN it is sometimes needed (on fixed disks)
if (!GetDiskFreeSpace(
szDrive,
&SectorsPerCluster,
&BytesPerSector,
&NumberOfFreeClusters,
&TotalNumberOfClusters))
return 0;
}
__int64 total = SectorsPerCluster * BytesPerSector * NumberOfFreeClusters;
return (DWORD)total;
}
bool ZipPlatform::GetFileSize(LPCTSTR lpszFileName, DWORD& dSize)
{
HANDLE f = CreateFile(lpszFileName, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
if (!f)
return false;
DWORD dwSize;
dwSize = ::GetFileSize(f, NULL);
CloseHandle(f);
if (dwSize == 0xFFFFFFFF)
return false;
dSize = dwSize;
return true;
}
CZipString ZipPlatform::GetTmpFileName(LPCTSTR lpszPath, DWORD iSizeNeeded)
{
TCHAR empty[] = _T("");
CZipString tempPath;
bool bCheckTemp = true;
if (lpszPath)
{
tempPath = lpszPath;
bCheckTemp = GetDeviceFreeSpace(tempPath) < iSizeNeeded;
}
if (bCheckTemp)
{
DWORD size = GetTempPath(0, NULL);
if (size == 0)
return empty;
GetTempPath(size, tempPath.GetBuffer(size));
tempPath.ReleaseBuffer();
if (GetDeviceFreeSpace(tempPath) < iSizeNeeded)
{
if (!GetCurrentDirectory(tempPath) || GetDeviceFreeSpace(tempPath) < iSizeNeeded)
return empty;
}
}
CZipString tempName;
if (!GetTempFileName(tempPath, _T("ZAR"), 0, tempName.GetBuffer(_MAX_PATH)))
return empty;
tempName.ReleaseBuffer();
return tempName;
}
bool ZipPlatform::GetCurrentDirectory(CZipString& sz)
{
DWORD i = ::GetCurrentDirectory(0, NULL);
if (!i)
return false;
TCHAR* pBuf = new TCHAR[i];
bool b = true;
if (!::GetCurrentDirectory(i, pBuf))
b = false;
else
sz = pBuf;
delete[] pBuf;
return b;
}
bool ZipPlatform::SetFileAttr(LPCTSTR lpFileName, DWORD uAttr)
{
return ::SetFileAttributes(lpFileName, uAttr) != 0;
}
bool ZipPlatform::GetFileAttr(LPCTSTR lpFileName, DWORD& uAttr)
{
// not using MFC due to MFC bug (attr is one byte there)
DWORD temp = ::GetFileAttributes(lpFileName);
if (temp == ( DWORD )-1)
return false;
uAttr = temp;
return true;
}
bool ZipPlatform::GetFileModTime(LPCTSTR lpFileName, time_t & ttime)
{
#if defined _MSC_VER && !defined __BORLANDC__ /*_MSC_VER may be defined in Borland after converting the VC project */
struct _stat st;
if (_tstat(lpFileName, &st) != 0)
#else
struct stat st;
if (stat(lpFileName, &st) != 0)
#endif
return false;
ttime = st.st_mtime;
return ttime != -1;
}
bool ZipPlatform::SetFileModTime(LPCTSTR lpFileName, time_t ttime)
{
struct _utimbuf ub;
ub.actime = time(NULL);
ub.modtime = ttime == -1 ? time(NULL) : ttime; // if wrong file time, set it to the current
return _tutime(lpFileName, &ub) == 0;
}
bool ZipPlatform::ChangeDirectory(LPCTSTR lpDirectory)
{
return _tchdir(lpDirectory) == 0; // returns 0 if ok
}
int ZipPlatform::FileExists(LPCTSTR lpszName)
{
if (_taccess(lpszName, 0) == 0)
{
if (DirectoryExists(lpszName))
return -1;
return 1;
}
else
return 0;
}
ZIPINLINE bool ZipPlatform::IsDriveRemovable(LPCTSTR lpszFilePath)
{
CZipPathComponent zpc(lpszFilePath);
return ::GetDriveType(zpc.GetFileDrive()) == DRIVE_REMOVABLE;
}
ZIPINLINE bool ZipPlatform::SetVolLabel(LPCTSTR lpszPath, LPCTSTR lpszLabel)
{
CZipPathComponent zpc(lpszPath);
CZipString szDrive = zpc.GetFileDrive();
CZipPathComponent::AppendSeparator(szDrive);
return ::SetVolumeLabel(szDrive, lpszLabel) != 0;
}
ZIPINLINE void ZipPlatform::AnsiOem(CZipAutoBuffer& buffer, bool bAnsiToOem)
{
if (bAnsiToOem)
CharToOemBuffA(buffer, buffer, buffer.GetSize());
else
OemToCharBuffA(buffer, buffer, buffer.GetSize());
}
ZIPINLINE bool ZipPlatform::RemoveFile(LPCTSTR lpszFileName, bool bThrow)
{
if (!::DeleteFile((LPTSTR)lpszFileName))
if (bThrow)
CZipException::Throw(CZipException::notRemoved, lpszFileName);
else
return false;
return true;
}
ZIPINLINE bool ZipPlatform::RenameFile( LPCTSTR lpszOldName, LPCTSTR lpszNewName, bool bThrow)
{
if (!::MoveFile((LPTSTR)lpszOldName, (LPTSTR)lpszNewName))
if (bThrow)
CZipException::Throw(CZipException::notRenamed, lpszOldName);
else
return false;
return true;
}
ZIPINLINE bool ZipPlatform::IsDirectory(DWORD uAttr)
{
return (uAttr & FILE_ATTRIBUTE_DIRECTORY) != 0;
}
ZIPINLINE bool ZipPlatform::CreateDirectory(LPCTSTR lpDirectory)
{
return ::CreateDirectory(lpDirectory, NULL) != 0;
}
ZIPINLINE DWORD ZipPlatform::GetDefaultAttributes()
{
return 0x81a40020; // make it readable under Unix
}
ZIPINLINE DWORD ZipPlatform::GetDefaultDirAttributes()
{
return 0x41ff0010; // make it readable under Unix
}
ZIPINLINE int ZipPlatform::GetSystemID()
{
return ZipCompatibility::zcDosFat;
}
ZIPINLINE bool ZipPlatform::GetSystemCaseSensitivity()
{
return false;
}
#ifdef _UNICODE
int ZipPlatform::WideToSingle(LPCTSTR lpWide, CZipAutoBuffer &szSingle)
{
size_t wideLen = wcslen(lpWide);
if (wideLen == 0)
{
szSingle.Release();
return 0;
}
// iLen does not include terminating character
int iLen = WideCharToMultiByte(CP_ACP,0, lpWide, wideLen, szSingle,
0, NULL, NULL);
if (iLen > 0)
{
szSingle.Allocate(iLen, true);
iLen = WideCharToMultiByte(CP_ACP,0, lpWide , wideLen, szSingle,
iLen, NULL, NULL);
ASSERT(iLen != 0);
}
else // here it means error
{
szSingle.Release();
iLen --;
}
return iLen;
}
int ZipPlatform::SingleToWide(const CZipAutoBuffer &szSingle, CZipString& szWide)
{
int singleLen = szSingle.GetSize();
// iLen doesn't include terminating character
int iLen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szSingle.GetBuffer(), singleLen, NULL, 0);
if (iLen > 0)
{
iLen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szSingle.GetBuffer(), singleLen,
szWide.GetBuffer(iLen) , iLen);
szWide.ReleaseBuffer(iLen);
ASSERT(iLen != 0);
}
else
{
szWide.Empty();
iLen --; // return -1
}
return iLen;
}
#endif
#ifndef _MFC_VER
#include <io.h>
#include <share.h>
bool ZipPlatform::TruncateFile(int iDes, DWORD iSize)
{
int ret = chsize(iDes, iSize);
return ret != -1;
}
int ZipPlatform::OpenFile(LPCTSTR lpszFileName, UINT iMode, int iShareMode)
{
switch (iShareMode)
{
case (CZipFile::shareDenyWrite & CZipFile::shareDenyRead):
iShareMode = SH_DENYRW;
break;
case (CZipFile::shareDenyRead):
iShareMode = SH_DENYRD;
break;
case (CZipFile::shareDenyWrite):
iShareMode = SH_DENYWR;
break;
default:
iShareMode = SH_DENYNO;
}
return _tsopen(lpszFileName, iMode, iShareMode, S_IREAD | S_IWRITE /*required only when O_CREAT mode*/);
}
bool ZipPlatform::FlushFile(int iDes)
{
return _commit(iDes) == 0;
}
int ZipPlatform::GetFileSystemHandle(int iDes)
{
return _get_osfhandle(iDes);
}
#endif //_MFC_VER

View File

@@ -0,0 +1,48 @@
////////////////////////////////////////////////////////////////////////////////
// $Workfile: ZipPlatformComm.cpp $
// $Archive: /ZipArchive/ZipPlatformComm.cpp $
// $Date$ $Author$
////////////////////////////////////////////////////////////////////////////////
// This source file is part of the ZipArchive library source distribution and
// is Copyright 2000-2003 by Tadeusz Dracz (http://www.artpol-software.com/)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// For the licensing details see the file License.txt
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "zipplatform.h"
using namespace ZipPlatform;
bool ZipPlatform::DirectoryExists(LPCTSTR lpszDir)
{
CZipString sz;
if (!GetCurrentDirectory(sz))
return false;
if (!ChangeDirectory(lpszDir))
return false;
ChangeDirectory(sz);
return true;
}
bool ZipPlatform::ForceDirectory(LPCTSTR lpDirectory)
{
ASSERT(lpDirectory);
CZipString szDirectory = lpDirectory;
szDirectory.TrimRight(CZipPathComponent::m_cSeparator);
CZipPathComponent zpc(szDirectory);
if ((zpc.GetFilePath() == szDirectory) ||
(FileExists(szDirectory) == -1))
return true;
if (!ForceDirectory(zpc.GetFilePath()))
return false;
if (!CreateDirectory(szDirectory))
return false;
return true;
}

View File

@@ -0,0 +1,461 @@
////////////////////////////////////////////////////////////////////////////////
// $Workfile: ZipStorage.cpp $
// $Archive: /ZipArchive/ZipStorage.cpp $
// $Date$ $Author$
////////////////////////////////////////////////////////////////////////////////
// This source file is part of the ZipArchive library source distribution and
// is Copyright 2000-2003 by Tadeusz Dracz (http://www.artpol-software.com/)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// For the licensing details see the file License.txt
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "zipstorage.h"
#include "ziparchive.h"
// #include "ZipPathComponent.h"
#include "zipplatform.h"
//////////////////////////////////////////////////////////////////////
// disk spanning objectives:
// - sinature at the first disk at the beginning
// - headers and central dir records not divided between disks
// - each file has a data descriptor preceded by the signature
// (bit 3 set in flag);
int CZipActionCallback::m_iStep = 256;
char CZipStorage::m_gszExtHeaderSignat[] = {0x50, 0x4b, 0x07, 0x08};
CZipStorage::CZipStorage()
{
m_pChangeDiskFunc = NULL;
m_iWriteBufferSize = 65536;
m_iCurrentDisk = -1;
m_pFile = NULL;
}
CZipStorage::~CZipStorage()
{
}
DWORD CZipStorage::Read(void *pBuf, DWORD iSize, bool bAtOnce)
{
if (iSize == 0)
return 0;
DWORD iRead = 0;
while (!iRead)
{
iRead = m_pFile->Read(pBuf, iSize);
if (!iRead)
if (IsSpanMode())
ChangeDisk(m_iCurrentDisk + 1);
else
ThrowError(CZipException::badZipFile);
}
if (iRead == iSize)
return iRead;
else if (bAtOnce || !IsSpanMode())
ThrowError(CZipException::badZipFile);
while (iRead < iSize)
{
ChangeDisk(m_iCurrentDisk + 1);
UINT iNewRead = m_pFile->Read((char*)pBuf + iRead, iSize - iRead);
if (!iNewRead && iRead < iSize)
ThrowError(CZipException::badZipFile);
iRead += iNewRead;
}
return iRead;
}
void CZipStorage::Open(LPCTSTR szPathName, int iMode, int iVolumeSize)
{
m_pWriteBuffer.Allocate(m_iWriteBufferSize);
m_uBytesInWriteBuffer = 0;
m_bNewSpan = false;
m_pFile = &m_internalfile;
m_bInMemory = false;
if ((iMode == CZipArchive::zipCreate) ||(iMode == CZipArchive::zipCreateSpan)) // create new archive
{
m_bReadOnly = false;
m_iCurrentDisk = 0;
if (iMode == CZipArchive::zipCreate)
{
m_iSpanMode = noSpan;
OpenFile(szPathName, CZipFile::modeCreate | CZipFile::modeReadWrite);
}
else // create disk spanning archive
{
m_bNewSpan = true;
m_iBytesWritten = 0;
if (iVolumeSize <= 0) // pkzip span
{
if (!m_pChangeDiskFunc)
ThrowError(CZipException::noCallback);
if (!ZipPlatform::IsDriveRemovable(szPathName))
ThrowError(CZipException::nonRemovable);
m_iSpanMode = pkzipSpan;
}
else
{
m_iTdSpanData = iVolumeSize;
m_iSpanMode = tdSpan;
}
NextDisk(4, szPathName);
Write(m_gszExtHeaderSignat, 4, true);
}
}
else // open existing
{
m_bReadOnly = iMode == CZipArchive::zipOpenReadOnly;
OpenFile(szPathName, CZipFile::modeNoTruncate |
(m_bReadOnly ? CZipFile::modeRead : CZipFile::modeReadWrite));
// m_uData, i m_iSpanMode are automatically set during reading the central dir
m_iSpanMode = iVolumeSize == 0 ? suggestedAuto : suggestedTd;
}
}
void CZipStorage::Open(CZipMemFile& mf, int iMode)
{
m_pWriteBuffer.Allocate(m_iWriteBufferSize);
m_uBytesInWriteBuffer = 0;
m_bNewSpan = false;
m_pFile = &mf;
m_bInMemory = true;
if (iMode == CZipArchive::zipCreate)
{
m_iCurrentDisk = 0;
m_iSpanMode = noSpan;
mf.SetLength(0);
}
else // open existing
{
mf.SeekToBegin();
m_iSpanMode = suggestedAuto;
}
}
void CZipStorage::ChangeDisk(int iNumber)
{
if (iNumber == m_iCurrentDisk)
return;
ASSERT(m_iSpanMode != noSpan);
m_iCurrentDisk = iNumber;
OpenFile(m_iSpanMode == pkzipSpan ? ChangePkzipRead() : ChangeTdRead(),
CZipFile::modeNoTruncate | CZipFile::modeRead);
}
void CZipStorage::ThrowError(int err)
{
CZipException::Throw(err, m_pFile->GetFilePath());
}
bool CZipStorage::OpenFile(LPCTSTR lpszName, UINT uFlags, bool bThrow)
{
return m_pFile->Open(lpszName, uFlags | CZipFile::shareDenyWrite, bThrow);
}
CZipString CZipStorage::ChangePkzipRead()
{
CZipString szTemp = m_pFile->GetFilePath();
m_pFile->Close();
CallCallback(-1 , szTemp);
return szTemp;
}
CZipString CZipStorage::ChangeTdRead()
{
CZipString szTemp = GetTdVolumeName(m_iCurrentDisk == m_iTdSpanData);
m_pFile->Close();
return szTemp;
}
CZipString CZipStorage::RenameLastFileInTDSpan()
{
ASSERT(m_iSpanMode == tdSpan);
// give to the last volume the zip extension
CZipString szFileName = m_pFile->GetFilePath();
CZipString szNewFileName = GetTdVolumeName(true);
if (!m_bInMemory)
{
m_pFile->Flush();
m_pFile->Close();
}
if (ZipPlatform::FileExists(szNewFileName))
ZipPlatform::RemoveFile(szNewFileName);
ZipPlatform::RenameFile(szFileName, szNewFileName);
return szNewFileName;
}
CZipString CZipStorage::Close(bool bAfterException)
{
bool bClose = true;
CZipString sz;
if (!bAfterException)
{
Flush();
if ((m_iSpanMode == tdSpan) && (m_bNewSpan))
{
sz = RenameLastFileInTDSpan();
bClose = false;// already closed in RenameLastFileInTDSpan
}
}
if (sz.IsEmpty())
sz = m_pFile->GetFilePath();
if (bClose && !m_bInMemory)
{
FlushFile();
m_pFile->Close();
}
m_pWriteBuffer.Release();
m_iCurrentDisk = -1;
m_iSpanMode = noSpan;
m_pFile = NULL;
return sz;
}
CZipString CZipStorage::GetTdVolumeName(bool bLast, LPCTSTR lpszZipName) const
{
CZipString szFilePath = lpszZipName ? lpszZipName : (LPCTSTR)m_pFile->GetFilePath();
CZipPathComponent zpc(szFilePath);
CZipString szExt;
if (bLast)
szExt = m_szSpanExtension;
else
szExt.Format(_T("%.3d"), m_iCurrentDisk);
zpc.SetExtension(szExt);
return zpc.GetFullPath();
}
void CZipStorage::NextDisk(int iNeeded, LPCTSTR lpszFileName)
{
Flush();
ASSERT(m_iSpanMode != noSpan);
if (m_iBytesWritten)
{
m_iBytesWritten = 0;
m_iCurrentDisk++;
if (m_iCurrentDisk >= 999)
ThrowError(CZipException::tooManyVolumes);
}
CZipString szFileName;
bool bPkSpan = (m_iSpanMode == pkzipSpan);
if (bPkSpan)
szFileName = lpszFileName ? lpszFileName : (LPCTSTR)m_pFile->GetFilePath();
else
szFileName = GetTdVolumeName(false, lpszFileName);
if (!m_pFile->IsClosed())
{
m_pFile->Flush();
m_pFile->Close();
}
if (bPkSpan)
{
int iCode = iNeeded;
while (true)
{
CallCallback(iCode, szFileName);
if (ZipPlatform::FileExists(szFileName))
iCode = -2;
else
{
CZipString label;
label.Format(_T("pkback# %.3d"), m_iCurrentDisk + 1);
if (!ZipPlatform::SetVolLabel(szFileName, label))
iCode = -3;
else if (!OpenFile(szFileName, CZipFile::modeCreate | CZipFile::modeReadWrite, false))
iCode = -4;
else
break;
}
}
m_uCurrentVolSize = GetFreeVolumeSpace();
}
else
{
m_uCurrentVolSize = m_iTdSpanData;
OpenFile(szFileName, CZipFile::modeCreate | CZipFile::modeReadWrite);
}
}
void CZipStorage::CallCallback(int iCode, CZipString szTemp)
{
ASSERT(m_pChangeDiskFunc);
m_pChangeDiskFunc->m_szExternalFile = szTemp;
m_pChangeDiskFunc->m_uDiskNeeded = m_iCurrentDisk + 1;
if (!m_pChangeDiskFunc->Callback(iCode))
CZipException::Throw(CZipException::aborted, szTemp);
}
DWORD CZipStorage::GetFreeVolumeSpace() const
{
ASSERT (m_iSpanMode == pkzipSpan);
CZipString szTemp = m_pFile->GetFilePath();
if (szTemp.IsEmpty()) // called once when creating a disk spanning archive
return 0;
else
{
CZipPathComponent zpc(szTemp);
return ZipPlatform::GetDeviceFreeSpace(zpc.GetFilePath());
}
}
void CZipStorage::UpdateSpanMode(WORD uLastDisk)
{
m_iCurrentDisk = uLastDisk;
if (uLastDisk)
{
// disk spanning detected
CZipString szFilePath = m_pFile->GetFilePath();
if (m_iSpanMode == suggestedAuto)
m_iSpanMode = ZipPlatform::IsDriveRemovable(szFilePath) ?
pkzipSpan : tdSpan;
else
{
ASSERT(m_iSpanMode == suggestedTd);
m_iSpanMode = tdSpan;
}
if (m_iSpanMode == pkzipSpan)
{
if (!m_pChangeDiskFunc)
ThrowError(CZipException::noCallback);
}
else /*if (m_iSpanMode == tdSpan)*/
m_iTdSpanData = uLastDisk; // disk with .zip extension ( the last one)
CZipPathComponent zpc(szFilePath);
m_szSpanExtension = zpc.GetFileExt();
m_pWriteBuffer.Release(); // no need for this in this case
}
else
m_iSpanMode = noSpan;
}
void CZipStorage::Write(const void *pBuf, DWORD iSize, bool bAtOnce)
{
if (!IsSpanMode())
WriteInternalBuffer((char*)pBuf, iSize);
else
{
// if not at once, one byte is enough free space
DWORD iNeeded = bAtOnce ? iSize : 1;
DWORD uTotal = 0;
while (uTotal < iSize)
{
DWORD uFree;
while ((uFree = VolumeLeft()) < iNeeded)
{
if ((m_iSpanMode == tdSpan) && !m_iBytesWritten && !m_uBytesInWriteBuffer)
// in the tdSpan mode, if the size of the archive is less
// than the size of the packet to be written at once,
// increase once the size of the volume
m_uCurrentVolSize = iNeeded;
else
NextDisk(iNeeded);
}
DWORD uLeftToWrite = iSize - uTotal;
DWORD uToWrite = uFree < uLeftToWrite ? uFree : uLeftToWrite;
WriteInternalBuffer((char*)pBuf + uTotal, uToWrite);
if (bAtOnce)
return;
else
uTotal += uToWrite;
}
}
}
void CZipStorage::WriteInternalBuffer(const char *pBuf, DWORD uSize)
{
DWORD uWritten = 0;
while (uWritten < uSize)
{
DWORD uFreeInBuffer = GetFreeInBuffer();
if (uFreeInBuffer == 0)
{
Flush();
uFreeInBuffer = m_pWriteBuffer.GetSize();
}
DWORD uLeftToWrite = uSize - uWritten;
DWORD uToCopy = uLeftToWrite < uFreeInBuffer ? uLeftToWrite : uFreeInBuffer;
memcpy(m_pWriteBuffer + m_uBytesInWriteBuffer, pBuf + uWritten, uToCopy);
uWritten += uToCopy;
m_uBytesInWriteBuffer += uToCopy;
}
}
DWORD CZipStorage::VolumeLeft() const
{
// for pkzip span m_uCurrentVolSize is updated after each flush()
return m_uCurrentVolSize - m_uBytesInWriteBuffer - ((m_iSpanMode == pkzipSpan) ? 0 : m_iBytesWritten);
}
void CZipStorage::Flush()
{
if (m_iSpanMode != noSpan)
m_iBytesWritten += m_uBytesInWriteBuffer;
if (m_uBytesInWriteBuffer)
{
m_pFile->Write(m_pWriteBuffer, m_uBytesInWriteBuffer);
m_uBytesInWriteBuffer = 0;
}
if (m_iSpanMode == pkzipSpan)
// after writing it is difficult to predict the free space due to
// not completly written clusters, write operation may start from
// the new cluster
m_uCurrentVolSize = GetFreeVolumeSpace();
}
void CZipStorage::FinalizeSpan()
{
ASSERT(IsSpanMode() == 1); // span in creation
ASSERT(!m_bInMemory);
CZipString szFileName;
if ((m_iSpanMode == tdSpan) && (m_bNewSpan))
szFileName = RenameLastFileInTDSpan();
else
{
szFileName = m_pFile->GetFilePath();
// the file is already closed
m_pFile->Close();
}
m_bNewSpan = false;
if (m_iCurrentDisk == 0) // one-disk span was converted to normal archive
m_iSpanMode = noSpan;
else
m_iTdSpanData = m_iCurrentDisk;
OpenFile(szFileName, CZipFile::modeNoTruncate | (m_iSpanMode == noSpan ? CZipFile::modeReadWrite : CZipFile::modeRead));
}