4.44 beta

This commit is contained in:
Igor Pavlov
2007-01-20 00:00:00 +00:00
committed by Kornel Lesiński
parent 804edc5756
commit d9666cf046
1331 changed files with 10535 additions and 13791 deletions

395
CPP/7zip/Archive/Cab/Cab.dsp Executable file
View File

@@ -0,0 +1,395 @@
# Microsoft Developer Studio Project File - Name="Cab" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=Cab - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "Cab.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "Cab.mak" CFG="Cab - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "Cab - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "Cab - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "Cab - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 1
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CAB_EXPORTS" /YX /FD /c
# ADD CPP /nologo /Gz /MD /W3 /GX /O1 /I "..\..\..\\" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CAB_EXPORTS" /FAs /Yu"StdAfx.h" /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x419 /d "NDEBUG"
# ADD RSC /l 0x419 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Program Files\7-Zip\Formats\cab.dll" /opt:NOWIN98
# SUBTRACT LINK32 /pdb:none
!ELSEIF "$(CFG)" == "Cab - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 1
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CAB_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /Gz /MTd /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CAB_EXPORTS" /FAcs /Yu"StdAfx.h" /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x419 /d "_DEBUG"
# ADD RSC /l 0x419 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Program Files\7-Zip\Formats\cab.dll" /pdbtype:sept
!ENDIF
# Begin Target
# Name "Cab - Win32 Release"
# Name "Cab - Win32 Debug"
# Begin Group "Spec"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\Archive.def
# End Source File
# Begin Source File
SOURCE=.\DllExports.cpp
# End Source File
# Begin Source File
SOURCE=.\resource.rc
# End Source File
# Begin Source File
SOURCE=.\StdAfx.cpp
# ADD CPP /Yc
# End Source File
# Begin Source File
SOURCE=.\StdAfx.h
# End Source File
# End Group
# Begin Group "Common"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\..\Common\Alloc.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\Alloc.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\IntToString.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\IntToString.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\NewHandler.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\NewHandler.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\String.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\String.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\StringConvert.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\StringConvert.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\UTFConvert.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\UTFConvert.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\Vector.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\Vector.h
# End Source File
# End Group
# Begin Group "Windows"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\..\Windows\PropVariant.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\PropVariant.h
# End Source File
# End Group
# Begin Group "Engine"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\CabBlockInStream.cpp
# End Source File
# Begin Source File
SOURCE=.\CabBlockInStream.h
# End Source File
# Begin Source File
SOURCE=.\CabHandler.cpp
# End Source File
# Begin Source File
SOURCE=.\CabHandler.h
# End Source File
# Begin Source File
SOURCE=.\CabHeader.cpp
# End Source File
# Begin Source File
SOURCE=.\CabHeader.h
# End Source File
# Begin Source File
SOURCE=.\CabIn.cpp
# End Source File
# Begin Source File
SOURCE=.\CabIn.h
# End Source File
# Begin Source File
SOURCE=.\CabItem.h
# End Source File
# End Group
# Begin Group "7zip Common"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\Common\InBuffer.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Common\InBuffer.h
# End Source File
# Begin Source File
SOURCE=..\..\Common\LSBFDecoder.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Common\LSBFDecoder.h
# End Source File
# Begin Source File
SOURCE=..\..\Common\MSBFDecoder.h
# End Source File
# Begin Source File
SOURCE=..\..\Common\OutBuffer.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Common\OutBuffer.h
# End Source File
# Begin Source File
SOURCE=..\..\Common\StreamUtils.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Common\StreamUtils.h
# End Source File
# End Group
# Begin Group "Compress"
# PROP Default_Filter ""
# Begin Group "LZ"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\Compress\LZ\LZOutWindow.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Compress\LZ\LZOutWindow.h
# End Source File
# End Group
# Begin Group "Lzx"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\Compress\Lzx\Lzx.h
# End Source File
# Begin Source File
SOURCE=..\..\Compress\Lzx\Lzx86Converter.cpp
!IF "$(CFG)" == "Cab - Win32 Release"
# ADD CPP /O2
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "Cab - Win32 Debug"
!ENDIF
# End Source File
# Begin Source File
SOURCE=..\..\Compress\Lzx\Lzx86Converter.h
# End Source File
# Begin Source File
SOURCE=..\..\Compress\Lzx\LzxDecoder.cpp
!IF "$(CFG)" == "Cab - Win32 Release"
# ADD CPP /O2
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "Cab - Win32 Debug"
!ENDIF
# End Source File
# Begin Source File
SOURCE=..\..\Compress\Lzx\LzxDecoder.h
# End Source File
# End Group
# Begin Group "Deflate"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\Compress\Deflate\DeflateConst.h
# End Source File
# Begin Source File
SOURCE=..\..\Compress\Deflate\DeflateDecoder.cpp
!IF "$(CFG)" == "Cab - Win32 Release"
# ADD CPP /O2
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "Cab - Win32 Debug"
!ENDIF
# End Source File
# Begin Source File
SOURCE=..\..\Compress\Deflate\DeflateDecoder.h
# End Source File
# Begin Source File
SOURCE=..\..\Compress\Deflate\DeflateExtConst.h
# End Source File
# End Group
# Begin Group "Copy"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\Compress\Copy\CopyCoder.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Compress\Copy\CopyCoder.h
# End Source File
# End Group
# Begin Group "Quantum"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\Compress\Quantum\QuantumDecoder.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Compress\Quantum\QuantumDecoder.h
# End Source File
# End Group
# Begin Group "Huffman"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\Compress\Huffman\HuffmanDecoder.h
# End Source File
# End Group
# End Group
# Begin Source File
SOURCE=.\cab.ico
# End Source File
# End Target
# End Project

29
CPP/7zip/Archive/Cab/Cab.dsw Executable file
View File

@@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "Cab"=.\Cab.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View File

@@ -0,0 +1,194 @@
// CabBlockInStream.cpp
#include "StdAfx.h"
#include "Common/Alloc.h"
#include "Common/Defs.h"
#include "../../Common/StreamUtils.h"
#include "CabBlockInStream.h"
namespace NArchive {
namespace NCab {
static const UInt32 kBlockSize = (1 << 16);
bool CCabBlockInStream::Create()
{
if (!_buffer)
_buffer = (Byte *)::MyAlloc(kBlockSize);
return (_buffer != 0);
}
CCabBlockInStream::~CCabBlockInStream()
{
MyFree(_buffer);
}
class CCheckSum2
{
UInt32 m_Value;
int m_Pos;
Byte m_Hist[4];
public:
CCheckSum2(): m_Value(0){};
void Init() { m_Value = 0; m_Pos = 0; }
void Update(const void *data, UInt32 size);
void FinishDataUpdate()
{
for (int i = 0; i < m_Pos; i++)
m_Value ^= ((UInt32)(m_Hist[i])) << (8 * (m_Pos - i - 1));
}
void UpdateUInt32(UInt32 v) { m_Value ^= v; }
UInt32 GetResult() const { return m_Value; }
};
void CCheckSum2::Update(const void *data, UInt32 size)
{
UInt32 checkSum = m_Value;
const Byte *dataPointer = (const Byte *)data;
while (size != 0 && m_Pos != 0)
{
m_Hist[m_Pos] = *dataPointer++;
m_Pos = (m_Pos + 1) & 3;
size--;
if (m_Pos == 0)
for (int i = 0; i < 4; i++)
checkSum ^= ((UInt32)m_Hist[i]) << (8 * i);
}
int numWords = size / 4;
while (numWords-- != 0)
{
UInt32 temp = *dataPointer++;
temp |= ((UInt32)(*dataPointer++)) << 8;
temp |= ((UInt32)(*dataPointer++)) << 16;
temp |= ((UInt32)(*dataPointer++)) << 24;
checkSum ^= temp;
}
m_Value = checkSum;
size &= 3;
while (size != 0)
{
m_Hist[m_Pos] = *dataPointer++;
m_Pos = (m_Pos + 1) & 3;
size--;
}
}
static const UInt32 kDataBlockHeaderSize = 8;
class CTempCabInBuffer2
{
public:
Byte Buffer[kDataBlockHeaderSize];
UInt32 Pos;
Byte ReadByte()
{
return Buffer[Pos++];
}
UInt32 ReadUInt32()
{
UInt32 value = 0;
for (int i = 0; i < 4; i++)
value |= (((UInt32)ReadByte()) << (8 * i));
return value;
}
UInt16 ReadUInt16()
{
UInt16 value = 0;
for (int i = 0; i < 2; i++)
value |= (((UInt16)ReadByte()) << (8 * i));
return value;
}
};
HRESULT CCabBlockInStream::PreRead(UInt32 &packSize, UInt32 &unpackSize)
{
CTempCabInBuffer2 inBuffer;
inBuffer.Pos = 0;
UInt32 processedSizeLoc;
RINOK(ReadStream(_stream, inBuffer.Buffer, kDataBlockHeaderSize, &processedSizeLoc))
if (processedSizeLoc != kDataBlockHeaderSize)
return S_FALSE; // bad block
UInt32 checkSum = inBuffer.ReadUInt32();
packSize = inBuffer.ReadUInt16();
unpackSize = inBuffer.ReadUInt16();
if (ReservedSize != 0)
{
RINOK(ReadStream(_stream, _buffer, ReservedSize, &processedSizeLoc));
if(ReservedSize != processedSizeLoc)
return S_FALSE; // bad block;
}
_pos = 0;
CCheckSum2 checkSumCalc;
checkSumCalc.Init();
UInt32 packSize2 = packSize;
if (MsZip && _size == 0)
{
if (packSize < 2)
return S_FALSE; // bad block;
Byte sig[2];
RINOK(ReadStream(_stream, sig, 2, &processedSizeLoc));
if(processedSizeLoc != 2)
return S_FALSE;
if (sig[0] != 0x43 || sig[1] != 0x4B)
return S_FALSE;
packSize2 -= 2;
checkSumCalc.Update(sig, 2);
}
if (kBlockSize - _size < packSize2)
return S_FALSE;
UInt32 curSize = packSize2;
if (curSize != 0)
{
RINOK(ReadStream(_stream, _buffer + _size, curSize, &processedSizeLoc));
checkSumCalc.Update(_buffer + _size, processedSizeLoc);
_size += processedSizeLoc;
if (processedSizeLoc != curSize)
return S_FALSE;
}
TotalPackSize = _size;
checkSumCalc.FinishDataUpdate();
bool dataError;
if (checkSum == 0)
dataError = false;
else
{
checkSumCalc.UpdateUInt32(packSize | (((UInt32)unpackSize) << 16));
dataError = (checkSumCalc.GetResult() != checkSum);
}
DataError |= dataError;
return dataError ? S_FALSE : S_OK;
}
STDMETHODIMP CCabBlockInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
{
if (processedSize != 0)
*processedSize = 0;
if (size == 0)
return S_OK;
if (_size != 0)
{
size = MyMin(_size, size);
memmove(data, _buffer + _pos, size);
_pos += size;
_size -= size;
if (processedSize != 0)
*processedSize = size;
return S_OK;
}
return S_OK; // no blocks data
}
}}

View File

@@ -0,0 +1,56 @@
// CabBlockInStream.cpp
#ifndef __CABBLOCKINSTREAM_H
#define __CABBLOCKINSTREAM_H
#include "Common/MyCom.h"
#include "../../IStream.h"
namespace NArchive {
namespace NCab {
class CCabBlockInStream:
public ISequentialInStream,
public CMyUnknownImp
{
CMyComPtr<ISequentialInStream> _stream;
Byte *_buffer;
UInt32 _pos;
UInt32 _size;
int _align;
public:
UInt32 TotalPackSize;
UInt32 ReservedSize;
bool DataError;
bool MsZip;
CCabBlockInStream(): _buffer(0), ReservedSize(0), MsZip(false), DataError(false), _align(0), TotalPackSize(0) {}
~CCabBlockInStream();
bool Create();
void SetStream(ISequentialInStream *stream) { _stream = stream; }
void InitForNewFolder()
{
_align = 0;
TotalPackSize = 0;
}
void InitForNewBlock()
{
_size = 0;
_align = (_align + (int)TotalPackSize) & 1;
}
int GetAlign() const { return _align; }
MY_UNKNOWN_IMP
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
HRESULT PreRead(UInt32 &packSize, UInt32 &unpackSize);
};
}}
#endif

View File

@@ -0,0 +1,812 @@
// CabHandler.cpp
#include "StdAfx.h"
#include "Common/StringConvert.h"
#include "Common/Defs.h"
#include "Common/Alloc.h"
#include "Common/UTFConvert.h"
#include "Common/ComTry.h"
#include "Common/IntToString.h"
#include "Windows/PropVariant.h"
#include "Windows/Time.h"
#include "CabHandler.h"
#include "CabBlockInStream.h"
#include "../../Compress/Copy/CopyCoder.h"
#include "../../Compress/Deflate/DeflateDecoder.h"
#include "../../Compress/Lzx/LzxDecoder.h"
#include "../../Compress/Quantum/QuantumDecoder.h"
#include "../Common/ItemNameUtils.h"
using namespace NWindows;
namespace NArchive {
namespace NCab {
// #define _CAB_DETAILS
#ifdef _CAB_DETAILS
enum
{
kpidBlockReal = kpidUserDefined,
kpidOffset,
kpidVolume,
};
#endif
STATPROPSTG kProperties[] =
{
{ NULL, kpidPath, VT_BSTR},
// { NULL, kpidIsFolder, VT_BOOL},
{ NULL, kpidSize, VT_UI8},
{ NULL, kpidLastWriteTime, VT_FILETIME},
{ NULL, kpidAttributes, VT_UI4},
{ NULL, kpidMethod, VT_BSTR},
{ NULL, kpidBlock, VT_I4}
#ifdef _CAB_DETAILS
,
{ L"BlockReal", kpidBlockReal, VT_UI4},
{ L"Offset", kpidOffset, VT_UI4},
{ L"Volume", kpidVolume, VT_UI4}
#endif
};
static const int kNumProperties = sizeof(kProperties) / sizeof(kProperties[0]);
static const wchar_t *kMethods[] =
{
L"None",
L"MSZip",
L"Quantum",
L"LZX"
};
static const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]);
static const wchar_t *kUnknownMethod = L"Unknown";
STDMETHODIMP CHandler::GetArchiveProperty(PROPID /* propID */, PROPVARIANT *value)
{
value->vt = VT_EMPTY;
return S_OK;
}
STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties)
{
*numProperties = sizeof(kProperties) / sizeof(kProperties[0]);
return S_OK;
}
STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index,
BSTR *name, PROPID *propID, VARTYPE *varType)
{
if(index >= sizeof(kProperties) / sizeof(kProperties[0]))
return E_INVALIDARG;
const STATPROPSTG &srcItem = kProperties[index];
*propID = srcItem.propid;
*varType = srcItem.vt;
if (srcItem.lpwstrName == 0)
*name = 0;
else
*name = ::SysAllocString(srcItem.lpwstrName);
return S_OK;
}
STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties)
{
*numProperties = 0;
return S_OK;
}
STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32 /* index */,
BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)
{
return E_INVALIDARG;
}
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant propVariant;
const CMvItem &mvItem = m_Database.Items[index];
const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex];
int itemIndex = mvItem.ItemIndex;
const CItem &item = db.Items[itemIndex];
switch(propID)
{
case kpidPath:
{
UString unicodeName;
if (item.IsNameUTF())
ConvertUTF8ToUnicode(item.Name, unicodeName);
else
unicodeName = MultiByteToUnicodeString(item.Name, CP_ACP);
propVariant = (const wchar_t *)NItemName::WinNameToOSName(unicodeName);
break;
}
case kpidIsFolder:
propVariant = item.IsDirectory();
break;
case kpidSize:
propVariant = item.Size;
break;
case kpidLastWriteTime:
{
FILETIME localFileTime, utcFileTime;
if (NTime::DosTimeToFileTime(item.Time, localFileTime))
{
if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
}
else
utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
propVariant = utcFileTime;
break;
}
case kpidAttributes:
propVariant = item.GetWinAttributes();
break;
case kpidMethod:
{
UInt32 realFolderIndex = item.GetFolderIndex(db.Folders.Size());
const CFolder &folder = db.Folders[realFolderIndex];
int methodIndex = folder.GetCompressionMethod();
UString method = (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod;
if (methodIndex == NHeader::NCompressionMethodMajor::kLZX ||
methodIndex == NHeader::NCompressionMethodMajor::kQuantum)
{
method += L":";
wchar_t temp[32];
ConvertUInt64ToString(folder.CompressionTypeMinor, temp);
method += temp;
}
propVariant = method;
break;
}
case kpidBlock:
propVariant = (Int32)m_Database.GetFolderIndex(&mvItem);
break;
#ifdef _CAB_DETAILS
case kpidBlockReal:
propVariant = UInt32(item.FolderIndex);
break;
case kpidOffset:
propVariant = (UInt32)item.Offset;
break;
case kpidVolume:
propVariant = (UInt32)mvItem.VolumeIndex;
break;
#endif
}
propVariant.Detach(value);
return S_OK;
COM_TRY_END
}
/*
class CPropgressImp: public CProgressVirt
{
CMyComPtr<IArchiveOpenCallback> m_OpenArchiveCallback;
public:
STDMETHOD(SetTotal)(const UInt64 *numFiles);
STDMETHOD(SetCompleted)(const UInt64 *numFiles);
void Init(IArchiveOpenCallback *openArchiveCallback)
{ m_OpenArchiveCallback = openArchiveCallback; }
};
STDMETHODIMP CPropgressImp::SetTotal(const UInt64 *numFiles)
{
if (m_OpenArchiveCallback)
return m_OpenArchiveCallback->SetCompleted(numFiles, NULL);
return S_OK;
}
STDMETHODIMP CPropgressImp::SetCompleted(const UInt64 *numFiles)
{
if (m_OpenArchiveCallback)
return m_OpenArchiveCallback->SetCompleted(numFiles, NULL);
return S_OK;
}
*/
STDMETHODIMP CHandler::Open(IInStream *inStream,
const UInt64 *maxCheckStartPosition,
IArchiveOpenCallback *openArchiveCallback)
{
COM_TRY_BEGIN
Close();
HRESULT res = S_FALSE;
CInArchive archive;
CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
{
CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openArchiveCallback;
openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback);
}
CMyComPtr<IInStream> nextStream = inStream;
bool prevChecked = false;
UInt64 numItems = 0;
try
{
while(nextStream != 0)
{
CDatabaseEx db;
db.Stream = nextStream;
res = archive.Open(maxCheckStartPosition, db);
if (res == S_OK)
{
if (!m_Database.Volumes.IsEmpty())
{
const CDatabaseEx &dbPrev = m_Database.Volumes[prevChecked ? m_Database.Volumes.Size() - 1 : 0];
if (dbPrev.ArchiveInfo.SetID != db.ArchiveInfo.SetID ||
dbPrev.ArchiveInfo.CabinetNumber + (prevChecked ? 1: - 1) !=
db.ArchiveInfo.CabinetNumber)
res = S_FALSE;
}
}
if (res == S_OK)
m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : 0, db);
else if (res != S_FALSE)
return res;
else
{
if (m_Database.Volumes.IsEmpty())
return S_FALSE;
if (prevChecked)
break;
prevChecked = true;
}
numItems += db.Items.Size();
RINOK(openArchiveCallback->SetCompleted(&numItems, NULL));
nextStream = 0;
for (;;)
{
const COtherArchive *otherArchive = 0;
if (!prevChecked)
{
const CInArchiveInfo &ai = m_Database.Volumes.Front().ArchiveInfo;
if (ai.IsTherePrev())
otherArchive = &ai.PreviousArchive;
else
prevChecked = true;
}
if (otherArchive == 0)
{
const CInArchiveInfo &ai = m_Database.Volumes.Back().ArchiveInfo;
if (ai.IsThereNext())
otherArchive = &ai.NextArchive;
}
if (!otherArchive)
break;
const UString fullName = MultiByteToUnicodeString(otherArchive->FileName, CP_ACP);
HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream);
if (result == S_OK)
break;
if (result != S_FALSE)
return result;
if (prevChecked)
break;
prevChecked = true;
}
}
if (res == S_OK)
{
m_Database.FillSortAndShrink();
if (!m_Database.Check())
res = S_FALSE;
}
}
catch(...)
{
res = S_FALSE;
}
if (res != S_OK)
{
Close();
return res;
}
COM_TRY_END
return S_OK;
}
STDMETHODIMP CHandler::Close()
{
m_Database.Clear();
return S_OK;
}
class CCabFolderOutStream:
public ISequentialOutStream,
public CMyUnknownImp
{
public:
MY_UNKNOWN_IMP
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
private:
const CMvDatabaseEx *m_Database;
const CRecordVector<bool> *m_ExtractStatuses;
int m_StartIndex;
int m_CurrentIndex;
CMyComPtr<IArchiveExtractCallback> m_ExtractCallback;
bool m_TestMode;
CMyComPtr<ISequentialOutStream> m_RealOutStream;
bool m_IsOk;
bool m_FileIsOpen;
UInt64 m_RemainFileSize;
UInt64 m_FolderSize;
UInt64 m_PosInFolder;
HRESULT OpenFile();
HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK);
public:
HRESULT WriteEmptyFiles();
void Init(
const CMvDatabaseEx *database,
const CRecordVector<bool> *extractStatuses,
int startIndex,
UInt64 folderSize,
IArchiveExtractCallback *extractCallback,
bool testMode);
HRESULT FlushCorrupted();
HRESULT Unsupported();
UInt64 GetRemain() const { return m_FolderSize - m_PosInFolder; }
UInt64 GetPosInFolder() const { return m_PosInFolder; }
};
void CCabFolderOutStream::Init(
const CMvDatabaseEx *database,
const CRecordVector<bool> *extractStatuses,
int startIndex,
UInt64 folderSize,
IArchiveExtractCallback *extractCallback,
bool testMode)
{
m_Database = database;
m_ExtractStatuses = extractStatuses;
m_StartIndex = startIndex;
m_FolderSize = folderSize;
m_ExtractCallback = extractCallback;
m_TestMode = testMode;
m_CurrentIndex = 0;
m_PosInFolder = 0;
m_FileIsOpen = false;
m_IsOk = true;
}
HRESULT CCabFolderOutStream::OpenFile()
{
Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? (m_TestMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract) :
NExtract::NAskMode::kSkip;
RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode));
if (!m_RealOutStream && !m_TestMode)
askMode = NArchive::NExtract::NAskMode::kSkip;
return m_ExtractCallback->PrepareOperation(askMode);
}
HRESULT CCabFolderOutStream::WriteEmptyFiles()
{
if (m_FileIsOpen)
return S_OK;
for(;m_CurrentIndex < m_ExtractStatuses->Size(); m_CurrentIndex++)
{
const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex];
const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
UInt64 fileSize = item.Size;
if (fileSize != 0)
return S_OK;
HRESULT result = OpenFile();
m_RealOutStream.Release();
RINOK(result);
RINOK(m_ExtractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
}
return S_OK;
}
// This is Write function
HRESULT CCabFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK)
{
UInt32 realProcessed = 0;
if (processedSize != NULL)
*processedSize = 0;
while(size != 0)
{
if (m_FileIsOpen)
{
UInt32 numBytesToWrite = (UInt32)MyMin(m_RemainFileSize, (UInt64)(size));
HRESULT res = S_OK;
if (numBytesToWrite > 0)
{
if (!isOK)
m_IsOk = false;
if (m_RealOutStream)
{
UInt32 processedSizeLocal = 0;
res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal);
numBytesToWrite = processedSizeLocal;
}
}
realProcessed += numBytesToWrite;
if (processedSize != NULL)
*processedSize = realProcessed;
data = (const void *)((const Byte *)data + numBytesToWrite);
size -= numBytesToWrite;
m_RemainFileSize -= numBytesToWrite;
m_PosInFolder += numBytesToWrite;
if (res != S_OK)
return res;
if (m_RemainFileSize == 0)
{
m_RealOutStream.Release();
RINOK(m_ExtractCallback->SetOperationResult(
m_IsOk ?
NArchive::NExtract::NOperationResult::kOK:
NArchive::NExtract::NOperationResult::kDataError));
m_FileIsOpen = false;
}
if (realProcessed > 0)
break; // with this break this function works as Write-Part
}
else
{
if (m_CurrentIndex >= m_ExtractStatuses->Size())
return E_FAIL;
const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex];
const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
m_RemainFileSize = item.Size;
UInt32 fileOffset = item.Offset;
if (fileOffset < m_PosInFolder)
return E_FAIL;
if (fileOffset > m_PosInFolder)
{
UInt32 numBytesToWrite = (UInt32)MyMin((UInt64)fileOffset - m_PosInFolder, UInt64(size));
realProcessed += numBytesToWrite;
if (processedSize != NULL)
*processedSize = realProcessed;
data = (const void *)((const Byte *)data + numBytesToWrite);
size -= numBytesToWrite;
m_PosInFolder += numBytesToWrite;
}
if (fileOffset == m_PosInFolder)
{
RINOK(OpenFile());
m_FileIsOpen = true;
m_CurrentIndex++;
m_IsOk = true;
}
}
}
return WriteEmptyFiles();
}
STDMETHODIMP CCabFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
{
return Write2(data, size, processedSize, true);
}
HRESULT CCabFolderOutStream::FlushCorrupted()
{
const UInt32 kBufferSize = (1 << 10);
Byte buffer[kBufferSize];
for (int i = 0; i < kBufferSize; i++)
buffer[i] = 0;
for (;;)
{
UInt64 remain = GetRemain();
if (remain == 0)
return S_OK;
UInt32 size = (UInt32)MyMin(remain, (UInt64)kBufferSize);
UInt32 processedSizeLocal = 0;
RINOK(Write2(buffer, size, &processedSizeLocal, false));
}
}
HRESULT CCabFolderOutStream::Unsupported()
{
while(m_CurrentIndex < m_ExtractStatuses->Size())
{
HRESULT result = OpenFile();
if (result != S_FALSE && result != S_OK)
return result;
m_RealOutStream.Release();
RINOK(m_ExtractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
m_CurrentIndex++;
}
return S_OK;
}
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
bool allFilesMode = (numItems == (UInt32)(-1));
if (allFilesMode)
numItems = m_Database.Items.Size();
if(numItems == 0)
return S_OK;
bool testMode = (_aTestMode != 0);
UInt64 totalUnPacked = 0;
UInt32 i;
int lastFolder = -2;
UInt64 lastFolderSize = 0;
for(i = 0; i < numItems; i++)
{
int index = allFilesMode ? i : indices[i];
const CMvItem &mvItem = m_Database.Items[index];
const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
if (item.IsDirectory())
continue;
int folderIndex = m_Database.GetFolderIndex(&mvItem);
if (folderIndex != lastFolder)
totalUnPacked += lastFolderSize;
lastFolder = folderIndex;
lastFolderSize = item.GetEndOffset();
}
totalUnPacked += lastFolderSize;
extractCallback->SetTotal(totalUnPacked);
totalUnPacked = 0;
NCompress::CCopyCoder *copyCoderSpec = NULL;
CMyComPtr<ICompressCoder> copyCoder;
NCompress::NDeflate::NDecoder::CCOMCoder *deflateDecoderSpec = NULL;
CMyComPtr<ICompressCoder> deflateDecoder;
NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL;
CMyComPtr<ICompressCoder> lzxDecoder;
NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL;
CMyComPtr<ICompressCoder> quantumDecoder;
CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream();
CMyComPtr<ISequentialInStream> cabBlockInStream = cabBlockInStreamSpec;
if (!cabBlockInStreamSpec->Create())
return E_OUTOFMEMORY;
CRecordVector<bool> extractStatuses;
for(i = 0; i < numItems;)
{
int index = allFilesMode ? i : indices[i];
const CMvItem &mvItem = m_Database.Items[index];
const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex];
int itemIndex = mvItem.ItemIndex;
const CItem &item = db.Items[itemIndex];
i++;
if (item.IsDirectory())
{
Int32 askMode= testMode ?
NArchive::NExtract::NAskMode::kTest :
NArchive::NExtract::NAskMode::kExtract;
CMyComPtr<ISequentialOutStream> realOutStream;
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
RINOK(extractCallback->PrepareOperation(askMode));
realOutStream.Release();
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
continue;
}
int folderIndex = m_Database.GetFolderIndex(&mvItem);
if (folderIndex < 0)
{
// If we need previous archive
Int32 askMode= testMode ?
NArchive::NExtract::NAskMode::kTest :
NArchive::NExtract::NAskMode::kExtract;
CMyComPtr<ISequentialOutStream> realOutStream;
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
RINOK(extractCallback->PrepareOperation(askMode));
realOutStream.Release();
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kDataError));
continue;
}
int startIndex2 = m_Database.FolderStartFileIndex[folderIndex];
int startIndex = startIndex2;
extractStatuses.Clear();
for (; startIndex < index; startIndex++)
extractStatuses.Add(false);
extractStatuses.Add(true);
startIndex++;
UInt64 curUnpack = item.GetEndOffset();
for(;i < numItems; i++)
{
int indexNext = allFilesMode ? i : indices[i];
const CMvItem &mvItem = m_Database.Items[indexNext];
const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
if (item.IsDirectory())
continue;
int newFolderIndex = m_Database.GetFolderIndex(&mvItem);
if (newFolderIndex != folderIndex)
break;
for (; startIndex < indexNext; startIndex++)
extractStatuses.Add(false);
extractStatuses.Add(true);
startIndex++;
curUnpack = item.GetEndOffset();
}
RINOK(extractCallback->SetCompleted(&totalUnPacked));
CCabFolderOutStream *cabFolderOutStream = new CCabFolderOutStream;
CMyComPtr<ISequentialOutStream> outStream(cabFolderOutStream);
const CFolder &folder = db.Folders[item.GetFolderIndex(db.Folders.Size())];
cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2,
curUnpack, extractCallback, testMode);
cabBlockInStreamSpec->MsZip = false;
switch(folder.GetCompressionMethod())
{
case NHeader::NCompressionMethodMajor::kNone:
if(copyCoderSpec == NULL)
{
copyCoderSpec = new NCompress::CCopyCoder;
copyCoder = copyCoderSpec;
}
break;
case NHeader::NCompressionMethodMajor::kMSZip:
if(deflateDecoderSpec == NULL)
{
deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder;
deflateDecoder = deflateDecoderSpec;
}
cabBlockInStreamSpec->MsZip = true;
break;
case NHeader::NCompressionMethodMajor::kLZX:
if(lzxDecoderSpec == NULL)
{
lzxDecoderSpec = new NCompress::NLzx::CDecoder;
lzxDecoder = lzxDecoderSpec;
}
RINOK(lzxDecoderSpec->SetParams(folder.CompressionTypeMinor));
break;
case NHeader::NCompressionMethodMajor::kQuantum:
if(quantumDecoderSpec == NULL)
{
quantumDecoderSpec = new NCompress::NQuantum::CDecoder;
quantumDecoder = quantumDecoderSpec;
}
quantumDecoderSpec->SetParams(folder.CompressionTypeMinor);
break;
default:
{
RINOK(cabFolderOutStream->Unsupported());
totalUnPacked += curUnpack;
continue;
}
}
cabBlockInStreamSpec->InitForNewFolder();
HRESULT res = S_OK;
{
int volIndex = mvItem.VolumeIndex;
int locFolderIndex = item.GetFolderIndex(db.Folders.Size());
bool keepHistory = false;
bool keepInputBuffer = false;
for (UInt32 f = 0; cabFolderOutStream->GetRemain() != 0;)
{
if (volIndex >= m_Database.Volumes.Size())
{
res = S_FALSE;
break;
}
const CDatabaseEx &db = m_Database.Volumes[volIndex];
const CFolder &folder = db.Folders[locFolderIndex];
if (f == 0)
{
cabBlockInStreamSpec->SetStream(db.Stream);
cabBlockInStreamSpec->ReservedSize = db.ArchiveInfo.GetDataBlockReserveSize();
RINOK(db.Stream->Seek(db.StartPosition + folder.DataStart, STREAM_SEEK_SET, NULL));
}
if (f == folder.NumDataBlocks)
{
volIndex++;
locFolderIndex = 0;
f = 0;
continue;
}
f++;
cabBlockInStreamSpec->DataError = false;
if (!keepInputBuffer)
cabBlockInStreamSpec->InitForNewBlock();
UInt32 packSize, unpackSize;
res = cabBlockInStreamSpec->PreRead(packSize, unpackSize);
if (res == S_FALSE)
break;
RINOK(res);
keepInputBuffer = (unpackSize == 0);
if (keepInputBuffer)
continue;
UInt64 totalUnPacked2 = totalUnPacked + cabFolderOutStream->GetPosInFolder();
RINOK(extractCallback->SetCompleted(&totalUnPacked2));
UInt64 unpackRemain = cabFolderOutStream->GetRemain();
const UInt32 kBlockSizeMax = (1 << 15);
if (unpackRemain > kBlockSizeMax)
unpackRemain = kBlockSizeMax;
if (unpackRemain > unpackSize)
unpackRemain = unpackSize;
switch(folder.GetCompressionMethod())
{
case NHeader::NCompressionMethodMajor::kNone:
res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
break;
case NHeader::NCompressionMethodMajor::kMSZip:
deflateDecoderSpec->SetKeepHistory(keepHistory);
res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
break;
case NHeader::NCompressionMethodMajor::kLZX:
lzxDecoderSpec->SetKeepHistory(keepHistory, cabBlockInStreamSpec->GetAlign());
res = lzxDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
break;
case NHeader::NCompressionMethodMajor::kQuantum:
quantumDecoderSpec->SetKeepHistory(keepHistory);
res = quantumDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
break;
}
if (res != S_OK)
{
if (res != S_FALSE)
RINOK(res);
break;
}
keepHistory = true;
}
if (res == S_OK)
{
RINOK(cabFolderOutStream->WriteEmptyFiles());
}
}
if (res != S_OK || cabFolderOutStream->GetRemain() != 0)
{
RINOK(cabFolderOutStream->FlushCorrupted());
}
totalUnPacked += curUnpack;
}
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
*numItems = m_Database.Items.Size();
return S_OK;
}
}}

View File

@@ -0,0 +1,45 @@
// CabHandler.h
#ifndef __CAB_HANDLER_H
#define __CAB_HANDLER_H
#include "Common/MyCom.h"
#include "../IArchive.h"
#include "CabIn.h"
namespace NArchive {
namespace NCab {
class CHandler:
public IInArchive,
public CMyUnknownImp
{
public:
MY_UNKNOWN_IMP
STDMETHOD(Open)(IInStream *stream,
const UInt64 *maxCheckStartPosition,
IArchiveOpenCallback *openArchiveCallback);
STDMETHOD(Close)();
STDMETHOD(GetNumberOfItems)(UInt32 *numItems);
STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback);
STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value);
STDMETHOD(GetNumberOfProperties)(UInt32 *numProperties);
STDMETHOD(GetPropertyInfo)(UInt32 index,
BSTR *name, PROPID *propID, VARTYPE *varType);
STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProperties);
STDMETHOD(GetArchivePropertyInfo)(UInt32 index,
BSTR *name, PROPID *propID, VARTYPE *varType);
private:
CMvDatabaseEx m_Database;
};
}}
#endif

View File

@@ -0,0 +1,19 @@
// Archive/Cab/Header.h
#include "StdAfx.h"
#include "CabHeader.h"
namespace NArchive{
namespace NCab{
namespace NHeader{
namespace NArchive {
UInt32 kSignature = 0x4643534d + 1;
static class CSignatureInitializer
{ public: CSignatureInitializer() { kSignature--; }} g_SignatureInitializer;
}
}}}

View File

@@ -0,0 +1,42 @@
// Archive/Cab/Header.h
#ifndef __ARCHIVE_CAB_HEADER_H
#define __ARCHIVE_CAB_HEADER_H
#include "Common/Types.h"
namespace NArchive {
namespace NCab {
namespace NHeader{
namespace NArchive
{
extern UInt32 kSignature;
namespace NFlags
{
const int kPrevCabinet = 0x0001;
const int kNextCabinet = 0x0002;
const int kReservePresent = 0x0004;
}
}
namespace NCompressionMethodMajor
{
const Byte kNone = 0;
const Byte kMSZip = 1;
const Byte kQuantum = 2;
const Byte kLZX = 3;
}
const int kFileNameIsUTFAttributeMask = 0x80;
namespace NFolderIndex
{
const int kContinuedFromPrev = 0xFFFD;
const int kContinuedToNext = 0xFFFE;
const int kContinuedPrevAndNext = 0xFFFF;
}
}}}
#endif

343
CPP/7zip/Archive/Cab/CabIn.cpp Executable file
View File

@@ -0,0 +1,343 @@
// Archive/CabIn.cpp
#include "StdAfx.h"
#include "Common/StringConvert.h"
#include "Common/MyCom.h"
#include "CabIn.h"
#include "Windows/Defs.h"
#include "../../Common/StreamUtils.h"
namespace NArchive{
namespace NCab{
/*
static HRESULT ReadBytes(IInStream *inStream, void *data, UInt32 size)
{
UInt32 realProcessedSize;
RINOK(ReadStream(inStream, data, size, &realProcessedSize));
if(realProcessedSize != size)
return S_FALSE;
return S_OK;
}
static HRESULT SafeRead(IInStream *inStream, void *data, UInt32 size)
{
UInt32 realProcessedSize;
RINOK(ReadStream(inStream, data, size, &realProcessedSize));
if(realProcessedSize != size)
throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
return S_OK;
}
static void SafeInByteRead(::CInBuffer &inBuffer, void *data, UInt32 size)
{
UInt32 realProcessedSize;
inBuffer.ReadBytes(data, size, realProcessedSize);
if(realProcessedSize != size)
throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
}
*/
Byte CInArchive::ReadByte()
{
Byte b;
if (!inBuffer.ReadByte(b))
throw CInArchiveException(CInArchiveException::kUnsupported);
return b;
}
UInt16 CInArchive::ReadUInt16()
{
UInt16 value = 0;
for (int i = 0; i < 2; i++)
{
Byte b = ReadByte();
value |= (UInt16(b) << (8 * i));
}
return value;
}
UInt32 CInArchive::ReadUInt32()
{
UInt32 value = 0;
for (int i = 0; i < 4; i++)
{
Byte b = ReadByte();
value |= (UInt32(b) << (8 * i));
}
return value;
}
AString CInArchive::SafeReadName()
{
AString name;
for (;;)
{
Byte b = ReadByte();
if (b == 0)
return name;
name += (char)b;
}
}
void CInArchive::ReadOtherArchive(COtherArchive &oa)
{
oa.FileName = SafeReadName();
oa.DiskName = SafeReadName();
}
void CInArchive::Skeep(size_t size)
{
while (size-- != 0)
ReadByte();
}
HRESULT CInArchive::Open2(IInStream *inStream,
const UInt64 *searchHeaderSizeLimit,
CDatabase &database)
{
database.Clear();
RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &database.StartPosition));
{
if (!inBuffer.Create(1 << 17))
return E_OUTOFMEMORY;
inBuffer.SetStream(inStream);
inBuffer.Init();
UInt64 value = 0;
const int kSignatureSize = 8;
UInt64 kSignature64 = NHeader::NArchive::kSignature;
for (;;)
{
Byte b;
if (!inBuffer.ReadByte(b))
return S_FALSE;
value >>= 8;
value |= ((UInt64)b) << ((kSignatureSize - 1) * 8);
if (inBuffer.GetProcessedSize() >= kSignatureSize)
{
if (value == kSignature64)
break;
if (searchHeaderSizeLimit != NULL)
if (inBuffer.GetProcessedSize() > (*searchHeaderSizeLimit))
return S_FALSE;
}
}
database.StartPosition += inBuffer.GetProcessedSize() - kSignatureSize;
}
CInArchiveInfo &archiveInfo = database.ArchiveInfo;
archiveInfo.Size = ReadUInt32(); // size of this cabinet file in bytes
if (ReadUInt32() != 0)
return S_FALSE;
archiveInfo.FileHeadersOffset = ReadUInt32(); // offset of the first CFFILE entry
if (ReadUInt32() != 0)
return S_FALSE;
archiveInfo.VersionMinor = ReadByte(); // cabinet file format version, minor
archiveInfo.VersionMajor = ReadByte(); // cabinet file format version, major
archiveInfo.NumFolders = ReadUInt16(); // number of CFFOLDER entries in this cabinet
archiveInfo.NumFiles = ReadUInt16(); // number of CFFILE entries in this cabinet
archiveInfo.Flags = ReadUInt16(); // number of CFFILE entries in this cabinet
archiveInfo.SetID = ReadUInt16(); // must be the same for all cabinets in a set
archiveInfo.CabinetNumber = ReadUInt16(); // number of this cabinet file in a set
if (archiveInfo.ReserveBlockPresent())
{
archiveInfo.PerCabinetAreaSize = ReadUInt16(); // (optional) size of per-cabinet reserved area
archiveInfo.PerFolderAreaSize = ReadByte(); // (optional) size of per-folder reserved area
archiveInfo.PerDataBlockAreaSize = ReadByte(); // (optional) size of per-datablock reserved area
Skeep(archiveInfo.PerCabinetAreaSize);
}
{
if (archiveInfo.IsTherePrev())
ReadOtherArchive(archiveInfo.PreviousArchive);
if (archiveInfo.IsThereNext())
ReadOtherArchive(archiveInfo.NextArchive);
}
int i;
for(i = 0; i < archiveInfo.NumFolders; i++)
{
CFolder folder;
folder.DataStart = ReadUInt32();
folder.NumDataBlocks = ReadUInt16();
folder.CompressionTypeMajor = ReadByte();
folder.CompressionTypeMinor = ReadByte();
Skeep(archiveInfo.PerFolderAreaSize);
database.Folders.Add(folder);
}
RINOK(inStream->Seek(database.StartPosition + archiveInfo.FileHeadersOffset, STREAM_SEEK_SET, NULL));
inBuffer.SetStream(inStream);
inBuffer.Init();
for(i = 0; i < archiveInfo.NumFiles; i++)
{
CItem item;
item.Size = ReadUInt32();
item.Offset = ReadUInt32();
item.FolderIndex = ReadUInt16();
UInt16 pureDate = ReadUInt16();
UInt16 pureTime = ReadUInt16();
item.Time = ((UInt32(pureDate) << 16)) | pureTime;
item.Attributes = ReadUInt16();
item.Name = SafeReadName();
int folderIndex = item.GetFolderIndex(database.Folders.Size());
if (folderIndex >= database.Folders.Size())
return S_FALSE;
database.Items.Add(item);
}
return S_OK;
}
#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
HRESULT CInArchive::Open(
const UInt64 *searchHeaderSizeLimit,
CDatabaseEx &database)
{
return Open2(database.Stream, searchHeaderSizeLimit, database);
}
static int CompareMvItems2(const CMvItem *p1, const CMvItem *p2)
{
RINOZ(MyCompare(p1->VolumeIndex, p2->VolumeIndex));
return MyCompare(p1->ItemIndex, p2->ItemIndex);
}
static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param)
{
const CMvDatabaseEx &mvDb = *(const CMvDatabaseEx *)param;
const CDatabaseEx &db1 = mvDb.Volumes[p1->VolumeIndex];
const CDatabaseEx &db2 = mvDb.Volumes[p2->VolumeIndex];
const CItem &item1 = db1.Items[p1->ItemIndex];
const CItem &item2 = db2.Items[p2->ItemIndex];;
bool isDir1 = item1.IsDirectory();
bool isDir2 = item2.IsDirectory();
if (isDir1 && !isDir2)
return -1;
if (isDir2 && !isDir1)
return 1;
int f1 = mvDb.GetFolderIndex(p1);
int f2 = mvDb.GetFolderIndex(p2);
RINOZ(MyCompare(f1, f2));
RINOZ(MyCompare(item1.Offset, item2.Offset));
RINOZ(MyCompare(item1.Size, item2.Size));
return CompareMvItems2(p1, p2);
}
bool CMvDatabaseEx::AreItemsEqual(int i1, int i2)
{
const CMvItem *p1 = &Items[i1];
const CMvItem *p2 = &Items[i2];
const CDatabaseEx &db1 = Volumes[p1->VolumeIndex];
const CDatabaseEx &db2 = Volumes[p2->VolumeIndex];
const CItem &item1 = db1.Items[p1->ItemIndex];
const CItem &item2 = db2.Items[p2->ItemIndex];;
int f1 = GetFolderIndex(p1);
int f2 = GetFolderIndex(p2);
if (f1 != f2)
return false;
if (item1.Offset != item2.Offset)
return false;
if (item1.Size != item2.Size)
return false;
return true;
}
void CMvDatabaseEx::FillSortAndShrink()
{
Items.Clear();
StartFolderOfVol.Clear();
FolderStartFileIndex.Clear();
int offset = 0;
for (int v = 0; v < Volumes.Size(); v++)
{
const CDatabaseEx &db = Volumes[v];
int curOffset = offset;
if (db.IsTherePrevFolder())
curOffset--;
StartFolderOfVol.Add(curOffset);
offset += db.GetNumberOfNewFolders();
CMvItem mvItem;
mvItem.VolumeIndex = v;
for (int i = 0 ; i < db.Items.Size(); i++)
{
mvItem.ItemIndex = i;
Items.Add(mvItem);
}
}
Items.Sort(CompareMvItems, (void *)this);
int j = 1;
int i;
for (i = 1; i < Items.Size(); i++)
if (!AreItemsEqual(i, i -1))
Items[j++] = Items[i];
Items.DeleteFrom(j);
for (i = 0; i < Items.Size(); i++)
{
const CMvItem &mvItem = Items[i];
int folderIndex = GetFolderIndex(&mvItem);
if (folderIndex >= FolderStartFileIndex.Size())
FolderStartFileIndex.Add(i);
}
}
bool CMvDatabaseEx::Check()
{
for (int v = 1; v < Volumes.Size(); v++)
{
const CDatabaseEx &db1 = Volumes[v];
if (db1.IsTherePrevFolder())
{
const CDatabaseEx &db0 = Volumes[v - 1];
if (db0.Folders.IsEmpty() || db1.Folders.IsEmpty())
return false;
const CFolder &f0 = db0.Folders.Back();
const CFolder &f1 = db1.Folders.Front();
if (f0.CompressionTypeMajor != f1.CompressionTypeMajor ||
f0.CompressionTypeMinor != f1.CompressionTypeMinor)
return false;
}
}
UInt64 maxPos = 0;
int prevFolder = -2;
for(int i = 0; i < Items.Size(); i++)
{
const CMvItem &mvItem = Items[i];
int fIndex = GetFolderIndex(&mvItem);
if (fIndex >= FolderStartFileIndex.Size())
return false;
const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
if (item.IsDirectory())
continue;
int folderIndex = GetFolderIndex(&mvItem);
if (folderIndex != prevFolder)
{
prevFolder = folderIndex;
maxPos = 0;
continue;
}
if (item.Offset < maxPos)
return false;
maxPos = item.GetEndOffset();
if (maxPos < item.Offset)
return false;
}
return true;
}
}}

166
CPP/7zip/Archive/Cab/CabIn.h Executable file
View File

@@ -0,0 +1,166 @@
// Archive/CabIn.h
#ifndef __ARCHIVE_CAB_IN_H
#define __ARCHIVE_CAB_IN_H
#include "../../IStream.h"
#include "../../Common/InBuffer.h"
#include "CabHeader.h"
#include "CabItem.h"
namespace NArchive {
namespace NCab {
class CInArchiveException
{
public:
enum CCauseType
{
kUnexpectedEndOfArchive = 0,
kIncorrectArchive,
kUnsupported,
} Cause;
CInArchiveException(CCauseType cause) : Cause(cause) {}
};
struct COtherArchive
{
AString FileName;
AString DiskName;
};
struct CArchiveInfo
{
Byte VersionMinor; /* cabinet file format version, minor */
Byte VersionMajor; /* cabinet file format version, major */
UInt16 NumFolders; /* number of CFFOLDER entries in this cabinet */
UInt16 NumFiles; /* number of CFFILE entries in this cabinet */
UInt16 Flags; /* cabinet file option indicators */
UInt16 SetID; /* must be the same for all cabinets in a set */
UInt16 CabinetNumber; /* number of this cabinet file in a set */
bool ReserveBlockPresent() const { return (Flags & NHeader::NArchive::NFlags::kReservePresent) != 0; }
bool IsTherePrev() const { return (Flags & NHeader::NArchive::NFlags::kPrevCabinet) != 0; }
bool IsThereNext() const { return (Flags & NHeader::NArchive::NFlags::kNextCabinet) != 0; }
UInt16 PerCabinetAreaSize; // (optional) size of per-cabinet reserved area
Byte PerFolderAreaSize; // (optional) size of per-folder reserved area
Byte PerDataBlockAreaSize; // (optional) size of per-datablock reserved area
Byte GetDataBlockReserveSize() const { return (Byte)(ReserveBlockPresent() ? PerDataBlockAreaSize : 0); }
COtherArchive PreviousArchive;
COtherArchive NextArchive;
CArchiveInfo()
{
Clear();
}
void Clear()
{
PerCabinetAreaSize = 0;
PerFolderAreaSize = 0;
PerDataBlockAreaSize = 0;
}
};
struct CInArchiveInfo: public CArchiveInfo
{
UInt32 Size; /* size of this cabinet file in bytes */
UInt32 FileHeadersOffset; // offset of the first CFFILE entry
};
class CDatabase
{
public:
UInt64 StartPosition;
CInArchiveInfo ArchiveInfo;
CObjectVector<CFolder> Folders;
CObjectVector<CItem> Items;
void Clear()
{
ArchiveInfo.Clear();
Folders.Clear();
Items.Clear();
}
bool IsTherePrevFolder() const
{
for (int i = 0; i < Items.Size(); i++)
if (Items[i].ContinuedFromPrev())
return true;
return false;
}
int GetNumberOfNewFolders() const
{
int res = Folders.Size();
if (IsTherePrevFolder())
res--;
return res;
}
UInt32 GetFileOffset(int index) const { return Items[index].Offset; }
UInt32 GetFileSize(int index) const { return Items[index].Size; }
};
class CDatabaseEx: public CDatabase
{
public:
CMyComPtr<IInStream> Stream;
};
struct CMvItem
{
int VolumeIndex;
int ItemIndex;
};
class CMvDatabaseEx
{
bool AreItemsEqual(int i1, int i2);
public:
CObjectVector<CDatabaseEx> Volumes;
CRecordVector<CMvItem> Items;
CRecordVector<int> StartFolderOfVol;
CRecordVector<int> FolderStartFileIndex;
int GetFolderIndex(const CMvItem *mvi) const
{
const CDatabaseEx &db = Volumes[mvi->VolumeIndex];
return StartFolderOfVol[mvi->VolumeIndex] +
db.Items[mvi->ItemIndex].GetFolderIndex(db.Folders.Size());
}
void Clear()
{
Volumes.Clear();
Items.Clear();
StartFolderOfVol.Clear();
FolderStartFileIndex.Clear();
}
void FillSortAndShrink();
bool Check();
};
class CInArchive
{
CInBuffer inBuffer;
Byte ReadByte();
UInt16 ReadUInt16();
UInt32 ReadUInt32();
AString SafeReadName();
void Skeep(size_t size);
void ReadOtherArchive(COtherArchive &oa);
HRESULT Open2(IInStream *inStream,
const UInt64 *searchHeaderSizeLimit,
CDatabase &database);
public:
HRESULT Open(
const UInt64 *searchHeaderSizeLimit,
CDatabaseEx &database);
};
}}
#endif

62
CPP/7zip/Archive/Cab/CabItem.h Executable file
View File

@@ -0,0 +1,62 @@
// Archive/CabItem.h
#ifndef __ARCHIVE_CAB_ITEM_H
#define __ARCHIVE_CAB_ITEM_H
#include "Common/Types.h"
#include "Common/String.h"
#include "CabHeader.h"
namespace NArchive {
namespace NCab {
struct CFolder
{
UInt32 DataStart; // offset of the first CFDATA block in this folder
UInt16 NumDataBlocks; // number of CFDATA blocks in this folder
Byte CompressionTypeMajor;
Byte CompressionTypeMinor;
Byte GetCompressionMethod() const { return (Byte)(CompressionTypeMajor & 0xF); }
};
class CItem
{
public:
AString Name;
UInt32 Offset;
UInt32 Size;
UInt32 Time;
UInt16 FolderIndex;
UInt16 Flags;
UInt16 Attributes;
UInt64 GetEndOffset() const { return (UInt64)Offset + Size; }
UInt32 GetWinAttributes() const { return (Attributes & ~NHeader::kFileNameIsUTFAttributeMask); }
bool IsNameUTF() const { return (Attributes & NHeader::kFileNameIsUTFAttributeMask) != 0; }
bool IsDirectory() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; }
bool ContinuedFromPrev() const
{
return
(FolderIndex == NHeader::NFolderIndex::kContinuedFromPrev) ||
(FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext);
}
bool ContinuedToNext() const
{
return
(FolderIndex == NHeader::NFolderIndex::kContinuedToNext) ||
(FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext);
}
int GetFolderIndex(int numFolders) const
{
if (ContinuedFromPrev())
return 0;
if (ContinuedToNext())
return (numFolders - 1);
return FolderIndex;
}
};
}}
#endif

View File

@@ -0,0 +1,72 @@
// DLLExports.cpp
#include "StdAfx.h"
#include "Common/MyInitGuid.h"
#include "Common/ComTry.h"
#include "Windows/PropVariant.h"
#include "CabHandler.h"
#include "../../ICoder.h"
// {23170F69-40C1-278A-1000-000110080000}
DEFINE_GUID(CLSID_CCabHandler,
0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0x00);
extern "C"
BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID)
{
return TRUE;
}
STDAPI CreateObject(
const GUID *classID,
const GUID *interfaceID,
void **outObject)
{
COM_TRY_BEGIN
*outObject = 0;
if (*classID != CLSID_CCabHandler)
return CLASS_E_CLASSNOTAVAILABLE;
if (*interfaceID != IID_IInArchive)
return E_NOINTERFACE;
CMyComPtr<IInArchive> inArchive = (IInArchive *)new NArchive::NCab::CHandler;
*outObject = inArchive.Detach();
COM_TRY_END
return S_OK;
}
STDAPI GetHandlerProperty(PROPID propID, PROPVARIANT *value)
{
NWindows::NCOM::CPropVariant propVariant;
switch(propID)
{
case NArchive::kName:
propVariant = L"Cab";
break;
case NArchive::kClassID:
{
if ((value->bstrVal = ::SysAllocStringByteLen(
(const char *)&CLSID_CCabHandler, sizeof(GUID))) != 0)
value->vt = VT_BSTR;
return S_OK;
}
case NArchive::kExtension:
propVariant = L"cab";
break;
case NArchive::kUpdate:
propVariant = false;
break;
case NArchive::kKeepName:
propVariant = false;
break;
case NArchive::kStartSignature:
{
const char sig[] = { 0x4D, 0x53, 0x43, 0x46 };
if ((value->bstrVal = ::SysAllocStringByteLen(sig, 4)) != 0)
value->vt = VT_BSTR;
return S_OK;
}
}
propVariant.Detach(value);
return S_OK;
}

View File

@@ -0,0 +1,3 @@
// StdAfx.cpp
#include "StdAfx.h"

8
CPP/7zip/Archive/Cab/StdAfx.h Executable file
View File

@@ -0,0 +1,8 @@
// StdAfx.h
#ifndef __STDAFX_H
#define __STDAFX_H
#include "../../../Common/MyWindows.h"
#endif

BIN
CPP/7zip/Archive/Cab/cab.ico Executable file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

70
CPP/7zip/Archive/Cab/makefile Executable file
View File

@@ -0,0 +1,70 @@
PROG = cab.dll
DEF_FILE = ../Archive.def
CFLAGS = $(CFLAGS) -I ../../../
LIBS = $(LIBS) oleaut32.lib user32.lib
CAB_OBJS = \
$O\DllExports.obj \
$O\CabBlockInStream.obj \
$O\CabHandler.obj \
$O\CabHeader.obj \
$O\CabIn.obj \
COMMON_OBJS = \
$O\Alloc.obj \
$O\IntToString.obj \
$O\NewHandler.obj \
$O\String.obj \
$O\StringConvert.obj \
$O\StringToInt.obj \
$O\UTFConvert.obj \
$O\Vector.obj \
WIN_OBJS = \
$O\PropVariant.obj \
7ZIP_COMMON_OBJS = \
$O\InBuffer.obj \
$O\LSBFDecoder.obj \
$O\OutBuffer.obj \
$O\ProgressUtils.obj \
$O\StreamUtils.obj \
COMPRESS_LZX_OBJS = \
$O\LzxDecoder.obj \
$O\Lzx86Converter.obj \
OBJS = \
$O\StdAfx.obj \
$(CAB_OBJS) \
$(COMMON_OBJS) \
$(WIN_OBJS) \
$(7ZIP_COMMON_OBJS) \
$(COMPRESS_LZX_OBJS) \
$O\DeflateDecoder.obj \
$O\QuantumDecoder.obj \
$O\LZOutWindow.obj \
$O\CopyCoder.obj \
$O\resource.res
!include "../../../Build.mak"
$(CAB_OBJS): $(*B).cpp
$(COMPL)
$(COMMON_OBJS): ../../../Common/$(*B).cpp
$(COMPL)
$(WIN_OBJS): ../../../Windows/$(*B).cpp
$(COMPL)
$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp
$(COMPL)
$(COMPRESS_LZX_OBJS): ../../Compress/Lzx/$(*B).cpp
$(COMPL_O2)
$O\DeflateDecoder.obj: ../../Compress/Deflate/$(*B).cpp
$(COMPL_O2)
$O\QuantumDecoder.obj: ../../Compress/Quantum/$(*B).cpp
$(COMPL)
$O\LZOutWindow.obj: ../../Compress/LZ/$(*B).cpp
$(COMPL)
$O\CopyCoder.obj: ../../Compress/Copy/$(*B).cpp
$(COMPL)

View File

@@ -0,0 +1,5 @@
#include "../../MyVersionInfo.rc"
MY_VERSION_INFO_DLL("Cab Plugin", "cab")
101 ICON "cab.ico"