Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Pavlov <ipavlov@users.sourceforge.net>2007-01-20 03:00:00 +0300
committerKornel LesiƄski <kornel@geekhood.net>2016-05-28 02:15:49 +0300
commitd9666cf046a8453b33b3e2fbf4d82295a9f87df3 (patch)
treec722ed19b844b53042aec0c1d7d2f8381140a5ed /CPP/7zip/Archive/Cab
parent804edc5756fede54dbb1aefda6d39d306111938d (diff)
4.44 beta
Diffstat (limited to 'CPP/7zip/Archive/Cab')
-rwxr-xr-xCPP/7zip/Archive/Cab/Cab.dsp395
-rwxr-xr-xCPP/7zip/Archive/Cab/Cab.dsw29
-rwxr-xr-xCPP/7zip/Archive/Cab/CabBlockInStream.cpp194
-rwxr-xr-xCPP/7zip/Archive/Cab/CabBlockInStream.h56
-rwxr-xr-xCPP/7zip/Archive/Cab/CabHandler.cpp812
-rwxr-xr-xCPP/7zip/Archive/Cab/CabHandler.h45
-rwxr-xr-xCPP/7zip/Archive/Cab/CabHeader.cpp19
-rwxr-xr-xCPP/7zip/Archive/Cab/CabHeader.h42
-rwxr-xr-xCPP/7zip/Archive/Cab/CabIn.cpp343
-rwxr-xr-xCPP/7zip/Archive/Cab/CabIn.h166
-rwxr-xr-xCPP/7zip/Archive/Cab/CabItem.h62
-rwxr-xr-xCPP/7zip/Archive/Cab/DllExports.cpp72
-rwxr-xr-xCPP/7zip/Archive/Cab/StdAfx.cpp3
-rwxr-xr-xCPP/7zip/Archive/Cab/StdAfx.h8
-rwxr-xr-xCPP/7zip/Archive/Cab/cab.icobin0 -> 3638 bytes
-rwxr-xr-xCPP/7zip/Archive/Cab/makefile70
-rwxr-xr-xCPP/7zip/Archive/Cab/resource.rc5
17 files changed, 2321 insertions, 0 deletions
diff --git a/CPP/7zip/Archive/Cab/Cab.dsp b/CPP/7zip/Archive/Cab/Cab.dsp
new file mode 100755
index 00000000..565661f6
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/Cab.dsp
@@ -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
diff --git a/CPP/7zip/Archive/Cab/Cab.dsw b/CPP/7zip/Archive/Cab/Cab.dsw
new file mode 100755
index 00000000..470cb1b3
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/Cab.dsw
@@ -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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp
new file mode 100755
index 00000000..b775c105
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp
@@ -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
+}
+
+}}
diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.h b/CPP/7zip/Archive/Cab/CabBlockInStream.h
new file mode 100755
index 00000000..46e15222
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabBlockInStream.h
@@ -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
diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp
new file mode 100755
index 00000000..cac79b11
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabHandler.cpp
@@ -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;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Cab/CabHandler.h b/CPP/7zip/Archive/Cab/CabHandler.h
new file mode 100755
index 00000000..245586b6
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabHandler.h
@@ -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
diff --git a/CPP/7zip/Archive/Cab/CabHeader.cpp b/CPP/7zip/Archive/Cab/CabHeader.cpp
new file mode 100755
index 00000000..37533dff
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabHeader.cpp
@@ -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;
+
+}
+
+}}}
diff --git a/CPP/7zip/Archive/Cab/CabHeader.h b/CPP/7zip/Archive/Cab/CabHeader.h
new file mode 100755
index 00000000..5c122743
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabHeader.h
@@ -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
diff --git a/CPP/7zip/Archive/Cab/CabIn.cpp b/CPP/7zip/Archive/Cab/CabIn.cpp
new file mode 100755
index 00000000..ae774f19
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabIn.cpp
@@ -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;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Cab/CabIn.h b/CPP/7zip/Archive/Cab/CabIn.h
new file mode 100755
index 00000000..aa3008f1
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabIn.h
@@ -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
diff --git a/CPP/7zip/Archive/Cab/CabItem.h b/CPP/7zip/Archive/Cab/CabItem.h
new file mode 100755
index 00000000..21327eca
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabItem.h
@@ -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
diff --git a/CPP/7zip/Archive/Cab/DllExports.cpp b/CPP/7zip/Archive/Cab/DllExports.cpp
new file mode 100755
index 00000000..fa17f10b
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/DllExports.cpp
@@ -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;
+}
diff --git a/CPP/7zip/Archive/Cab/StdAfx.cpp b/CPP/7zip/Archive/Cab/StdAfx.cpp
new file mode 100755
index 00000000..d0feea85
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Archive/Cab/StdAfx.h b/CPP/7zip/Archive/Cab/StdAfx.h
new file mode 100755
index 00000000..e7fb6986
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+
+#endif
diff --git a/CPP/7zip/Archive/Cab/cab.ico b/CPP/7zip/Archive/Cab/cab.ico
new file mode 100755
index 00000000..cc2007fc
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/cab.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Cab/makefile b/CPP/7zip/Archive/Cab/makefile
new file mode 100755
index 00000000..672afed3
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/makefile
@@ -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)
+
diff --git a/CPP/7zip/Archive/Cab/resource.rc b/CPP/7zip/Archive/Cab/resource.rc
new file mode 100755
index 00000000..fa0792bd
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/resource.rc
@@ -0,0 +1,5 @@
+#include "../../MyVersionInfo.rc"
+
+MY_VERSION_INFO_DLL("Cab Plugin", "cab")
+
+101 ICON "cab.ico"