Source code

Revision control

Copy as Markdown

Other Tools

// 7zUpdate.cpp↩
#include "StdAfx.h"
#include "../../../../C/CpuArch.h"
#include "../../../Common/Wildcard.h"
#include "../../Common/CreateCoder.h"
#include "../../Common/LimitedStreams.h"
#include "../../Common/ProgressUtils.h"
#include "../../Compress/CopyCoder.h"
#include "../Common/ItemNameUtils.h"
#include "7zDecode.h"
#include "7zEncode.h"
#include "7zFolderInStream.h"
#include "7zHandler.h"
#include "7zOut.h"
#include "7zUpdate.h"
namespace NArchive {↩
namespace N7z {↩
#define k_X86 k_BCJ↩
struct CFilterMode↩
{↩
UInt32 Id;↩
UInt32 Delta;↩
CFilterMode(): Id(0), Delta(0) {}↩
void SetDelta()↩
{↩
if (Id == k_IA64)↩
Delta = 16;↩
else if (Id == k_ARM || Id == k_PPC || Id == k_SPARC)↩
Delta = 4;↩
else if (Id == k_ARMT)↩
Delta = 2;↩
else
Delta = 0;↩
}↩
};↩
/* ---------- PE ---------- */
#define MZ_SIG 0x5A4D↩
#define PE_SIG 0x00004550↩
#define PE_OptHeader_Magic_32 0x10B↩
#define PE_OptHeader_Magic_64 0x20B↩
#define PE_SectHeaderSize 40↩
#define PE_SECT_EXECUTE 0x20000000↩
static int Parse_EXE(const Byte *buf, size_t size, CFilterMode *filterMode)↩
{↩
if (size < 512 || GetUi16(buf) != MZ_SIG)↩
return 0;↩
const Byte *p;↩
UInt32 peOffset, optHeaderSize, filterId;↩
peOffset = GetUi32(buf + 0x3C);↩
if (peOffset >= 0x1000 || peOffset + 512 > size || (peOffset & 7) != 0)↩
return 0;↩
p = buf + peOffset;↩
if (GetUi32(p) != PE_SIG)↩
return 0;↩
p += 4;↩
switch (GetUi16(p))↩
{↩
case 0x014C:↩
case 0x8664: filterId = k_X86; break;↩
/*↩
IMAGE_FILE_MACHINE_ARM 0x01C0 // ARM LE↩
IMAGE_FILE_MACHINE_THUMB 0x01C2 // ARM Thumb / Thumb-2 LE↩
IMAGE_FILE_MACHINE_ARMNT 0x01C4 // ARM Thumb-2, LE↩
Note: We use ARM filter for 0x01C2. (WinCE 5 - 0x01C2) files mostly contain ARM code (not Thumb/Thumb-2).↩
*/
case 0x01C0: // WinCE old↩
case 0x01C2: filterId = k_ARM; break; // WinCE new↩
case 0x01C4: filterId = k_ARMT; break; // WinRT↩
case 0x0200: filterId = k_IA64; break;↩
default: return 0;↩
}↩
optHeaderSize = GetUi16(p + 16);↩
if (optHeaderSize > (1 << 10))↩
return 0;↩
p += 20; /* headerSize */
switch (GetUi16(p))↩
{↩
case PE_OptHeader_Magic_32:↩
case PE_OptHeader_Magic_64:↩
break;↩
default:↩
return 0;↩
}↩
filterMode->Id = filterId;↩
return 1;↩
}↩
/* ---------- ELF ---------- */
#define ELF_SIG 0x464C457F↩
#define ELF_CLASS_32 1↩
#define ELF_CLASS_64 2↩
#define ELF_DATA_2LSB 1↩
#define ELF_DATA_2MSB 2↩
static UInt16 Get16(const Byte *p, Bool be) { if (be) return (UInt16)GetBe16(p); return (UInt16)GetUi16(p); }↩
static UInt32 Get32(const Byte *p, Bool be) { if (be) return GetBe32(p); return GetUi32(p); }↩
// static UInt64 Get64(const Byte *p, Bool be) { if (be) return GetBe64(p); return GetUi64(p); }↩
static int Parse_ELF(const Byte *buf, size_t size, CFilterMode *filterMode)↩
{↩
Bool /* is32, */ be;↩
UInt32 filterId;↩
if (size < 512 || buf[6] != 1) /* ver */
return 0;↩
if (GetUi32(buf) != ELF_SIG)↩
return 0;↩
switch (buf[4])↩
{↩
case ELF_CLASS_32: /* is32 = True; */ break;↩
case ELF_CLASS_64: /* is32 = False; */ break;↩
default: return 0;↩
}↩
switch (buf[5])↩
{↩
case ELF_DATA_2LSB: be = False; break;↩
case ELF_DATA_2MSB: be = True; break;↩
default: return 0;↩
}↩
switch (Get16(buf + 0x12, be))↩
{↩
case 3:↩
case 6:↩
case 62: filterId = k_X86; break;↩
case 2:↩
case 18:↩
case 43: filterId = k_SPARC; break;↩
case 20:↩
case 21: if (!be) return 0; filterId = k_PPC; break;↩
case 40: if ( be) return 0; filterId = k_ARM; break;↩
/* Some IA-64 ELF exacutable have size that is not aligned for 16 bytes.↩
So we don't use IA-64 filter for IA-64 ELF */
// case 50: if ( be) return 0; filterId = k_IA64; break;↩
default: return 0;↩
}↩
filterMode->Id = filterId;↩
return 1;↩
}↩
/* ---------- Mach-O ---------- */
#define MACH_SIG_BE_32 0xCEFAEDFE↩
#define MACH_SIG_BE_64 0xCFFAEDFE↩
#define MACH_SIG_LE_32 0xFEEDFACE↩
#define MACH_SIG_LE_64 0xFEEDFACF↩
#define MACH_ARCH_ABI64 (1 << 24)↩
#define MACH_MACHINE_386 7↩
#define MACH_MACHINE_ARM 12↩
#define MACH_MACHINE_SPARC 14↩
#define MACH_MACHINE_PPC 18↩
#define MACH_MACHINE_PPC64 (MACH_ARCH_ABI64 | MACH_MACHINE_PPC)↩
#define MACH_MACHINE_AMD64 (MACH_ARCH_ABI64 | MACH_MACHINE_386)↩
static unsigned Parse_MACH(const Byte *buf, size_t size, CFilterMode *filterMode)↩
{↩
UInt32 filterId, numCommands, commandsSize;↩
if (size < 512)↩
return 0;↩
Bool /* mode64, */ be;↩
switch (GetUi32(buf))↩
{↩
case MACH_SIG_BE_32: /* mode64 = False; */ be = True; break;↩
case MACH_SIG_BE_64: /* mode64 = True; */ be = True; break;↩
case MACH_SIG_LE_32: /* mode64 = False; */ be = False; break;↩
case MACH_SIG_LE_64: /* mode64 = True; */ be = False; break;↩
default: return 0;↩
}↩
switch (Get32(buf + 4, be))↩
{↩
case MACH_MACHINE_386:↩
case MACH_MACHINE_AMD64: filterId = k_X86; break;↩
case MACH_MACHINE_ARM: if ( be) return 0; filterId = k_ARM; break;↩
case MACH_MACHINE_SPARC: if (!be) return 0; filterId = k_SPARC; break;↩
case MACH_MACHINE_PPC:↩
case MACH_MACHINE_PPC64: if (!be) return 0; filterId = k_PPC; break;↩
default: return 0;↩
}↩
numCommands = Get32(buf + 0x10, be);↩
commandsSize = Get32(buf + 0x14, be);↩
if (commandsSize > (1 << 24) || numCommands > (1 << 18))↩
return 0;↩
filterMode->Id = filterId;↩
return 1;↩
}↩
/* ---------- WAV ---------- */
#define WAV_SUBCHUNK_fmt 0x20746D66↩
#define WAV_SUBCHUNK_data 0x61746164↩
#define RIFF_SIG 0x46464952↩
static Bool Parse_WAV(const Byte *buf, size_t size, CFilterMode *filterMode)↩
{↩
UInt32 subChunkSize, pos;↩
if (size < 0x2C)↩
return False;↩
if (GetUi32(buf + 0) != RIFF_SIG ||↩
GetUi32(buf + 8) != 0x45564157 || // WAVE↩
GetUi32(buf + 0xC) != WAV_SUBCHUNK_fmt)↩
return False;↩
subChunkSize = GetUi32(buf + 0x10);↩
/* [0x14 = format] = 1 (PCM) */
if (subChunkSize < 0x10 || subChunkSize > 0x12 || GetUi16(buf + 0x14) != 1)↩
return False;↩
unsigned numChannels = GetUi16(buf + 0x16);↩
unsigned bitsPerSample = GetUi16(buf + 0x22);↩
if ((bitsPerSample & 0x7) != 0 || bitsPerSample >= 256 || numChannels >= 256)↩
return False;↩
pos = 0x14 + subChunkSize;↩
const int kNumSubChunksTests = 10;↩
// Do we need to scan more than 3 sub-chunks?↩
for (int i = 0; i < kNumSubChunksTests; i++)↩
{↩
if (pos + 8 > size)↩
return False;↩
subChunkSize = GetUi32(buf + pos + 4);↩
if (GetUi32(buf + pos) == WAV_SUBCHUNK_data)↩
{↩
unsigned delta = numChannels * (bitsPerSample >> 3);↩
if (delta >= 256)↩
return False;↩
filterMode->Id = k_Delta;↩
filterMode->Delta = delta;↩
return True;↩
}↩
if (subChunkSize > (1 << 16))↩
return False;↩
pos += subChunkSize + 8;↩
}↩
return False;↩
}↩
static Bool ParseFile(const Byte *buf, size_t size, CFilterMode *filterMode)↩
{↩
filterMode->Id = 0;↩
filterMode->Delta = 0;↩
if (Parse_EXE(buf, size, filterMode)) return True;↩
if (Parse_ELF(buf, size, filterMode)) return True;↩
if (Parse_MACH(buf, size, filterMode)) return True;↩
return Parse_WAV(buf, size, filterMode);↩
}↩
struct CFilterMode2: public CFilterMode↩
{↩
bool Encrypted;↩
unsigned GroupIndex;↩
CFilterMode2(): Encrypted(false) {}↩
int Compare(const CFilterMode2 &m) const
{↩
if (!Encrypted)↩
{↩
if (m.Encrypted)↩
return -1;↩
}↩
else if (!m.Encrypted)↩
return 1;↩
if (Id < m.Id) return -1;↩
if (Id > m.Id) return 1;↩
if (Delta < m.Delta) return -1;↩
if (Delta > m.Delta) return 1;↩
return 0;↩
}↩
bool operator ==(const CFilterMode2 &m) const
{↩
return Id == m.Id && Delta == m.Delta && Encrypted == m.Encrypted;↩
}↩
};↩
static unsigned GetGroup(CRecordVector<CFilterMode2> &filters, const CFilterMode2 &m)↩
{↩
unsigned i;↩
for (i = 0; i < filters.Size(); i++)↩
{↩
const CFilterMode2 &m2 = filters[i];↩
if (m == m2)↩
return i;↩
/*↩
if (m.Encrypted != m2.Encrypted)↩
{↩
if (!m.Encrypted)↩
break;↩
continue;↩
}↩
if (m.Id < m2.Id) break;↩
if (m.Id != m2.Id) continue;↩
if (m.Delta < m2.Delta) break;↩
if (m.Delta != m2.Delta) continue;↩
*/
}↩
// filters.Insert(i, m);↩
// return i;↩
return filters.Add(m);↩
}↩
static inline bool Is86Filter(CMethodId m)↩
{↩
return (m == k_BCJ || m == k_BCJ2);↩
}↩
static inline bool IsExeFilter(CMethodId m)↩
{↩
switch (m)↩
{↩
case k_BCJ:↩
case k_BCJ2:↩
case k_ARM:↩
case k_ARMT:↩
case k_PPC:↩
case k_SPARC:↩
case k_IA64:↩
return true;↩
}↩
return false;↩
}↩
static unsigned Get_FilterGroup_for_Folder(↩
CRecordVector<CFilterMode2> &filters, const CFolderEx &f, bool extractFilter)↩
{↩
CFilterMode2 m;↩
m.Id = 0;↩
m.Delta = 0;↩
m.Encrypted = f.IsEncrypted();↩
if (extractFilter)↩
{↩
const CCoderInfo &coder = f.Coders[f.UnpackCoder];↩
if (coder.MethodID == k_Delta)↩
{↩
if (coder.Props.Size() == 1)↩
{↩
m.Delta = (unsigned)coder.Props[0] + 1;↩
m.Id = k_Delta;↩
}↩
}↩
else if (IsExeFilter(coder.MethodID))↩
{↩
m.Id = (UInt32)coder.MethodID;↩
if (m.Id == k_BCJ2)↩
m.Id = k_BCJ;↩
m.SetDelta();↩
}↩
}↩
return GetGroup(filters, m);↩
}↩
static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream,↩
UInt64 position, UInt64 size, ICompressProgressInfo *progress)↩
{↩
RINOK(inStream->Seek(position, STREAM_SEEK_SET, 0));↩
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;↩
CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec);↩
streamSpec->SetStream(inStream);↩
streamSpec->Init(size);↩
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;↩
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;↩
RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));↩
return (copyCoderSpec->TotalSize == size ? S_OK : E_FAIL);↩
}↩
/*↩
unsigned CUpdateItem::GetExtensionPos() const↩
{↩
int slashPos = Name.ReverseFind_PathSepar();↩
int dotPos = Name.ReverseFind_Dot();↩
if (dotPos <= slashPos)↩
return Name.Len();↩
return dotPos + 1;↩
}↩
UString CUpdateItem::GetExtension() const↩
{↩
return Name.Ptr(GetExtensionPos());↩
}↩
*/
#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }↩
#define RINOZ_COMP(a, b) RINOZ(MyCompare(a, b))↩
/*↩
static int CompareBuffers(const CByteBuffer &a1, const CByteBuffer &a2)↩
{↩
size_t c1 = a1.GetCapacity();↩
size_t c2 = a2.GetCapacity();↩
RINOZ_COMP(c1, c2);↩
for (size_t i = 0; i < c1; i++)↩
RINOZ_COMP(a1[i], a2[i]);↩
return 0;↩
}↩
static int CompareCoders(const CCoderInfo &c1, const CCoderInfo &c2)↩
{↩
RINOZ_COMP(c1.NumInStreams, c2.NumInStreams);↩
RINOZ_COMP(c1.NumOutStreams, c2.NumOutStreams);↩
RINOZ_COMP(c1.MethodID, c2.MethodID);↩
return CompareBuffers(c1.Props, c2.Props);↩
}↩
static int CompareBonds(const CBond &b1, const CBond &b2)↩
{↩
RINOZ_COMP(b1.InIndex, b2.InIndex);↩
return MyCompare(b1.OutIndex, b2.OutIndex);↩
}↩
static int CompareFolders(const CFolder &f1, const CFolder &f2)↩
{↩
int s1 = f1.Coders.Size();↩
int s2 = f2.Coders.Size();↩
RINOZ_COMP(s1, s2);↩
int i;↩
for (i = 0; i < s1; i++)↩
RINOZ(CompareCoders(f1.Coders[i], f2.Coders[i]));↩
s1 = f1.Bonds.Size();↩
s2 = f2.Bonds.Size();↩
RINOZ_COMP(s1, s2);↩
for (i = 0; i < s1; i++)↩
RINOZ(CompareBonds(f1.Bonds[i], f2.Bonds[i]));↩
return 0;↩
}↩
*/
/*↩
static int CompareFiles(const CFileItem &f1, const CFileItem &f2)↩
{↩
return CompareFileNames(f1.Name, f2.Name);↩
}↩
*/
struct CFolderRepack↩
{↩
unsigned FolderIndex;↩
CNum NumCopyFiles;↩
};↩
/*↩
static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void *)↩
{↩
int i1 = p1->FolderIndex;↩
int i2 = p2->FolderIndex;↩
// In that version we don't want to parse folders here, so we don't compare folders↩
// probably it must be improved in future↩
// const CDbEx &db = *(const CDbEx *)param;↩
// RINOZ(CompareFolders(↩
// db.Folders[i1],↩
// db.Folders[i2]));↩
return MyCompare(i1, i2);↩
// RINOZ_COMP(↩
// db.NumUnpackStreamsVector[i1],↩
// db.NumUnpackStreamsVector[i2]);↩
// if (db.NumUnpackStreamsVector[i1] == 0)↩
// return 0;↩
// return CompareFiles(↩
// db.Files[db.FolderStartFileIndex[i1]],↩
// db.Files[db.FolderStartFileIndex[i2]]);↩
}↩
*/
/*↩
we sort empty files and dirs in such order:↩
- Dir.NonAnti (name sorted)↩
- File.NonAnti (name sorted)↩
- File.Anti (name sorted)↩
- Dir.Anti (reverse name sorted)↩
*/
static int CompareEmptyItems(const unsigned *p1, const unsigned *p2, void *param)↩
{↩
const CObjectVector<CUpdateItem> &updateItems = *(const CObjectVector<CUpdateItem> *)param;↩
const CUpdateItem &u1 = updateItems[*p1];↩
const CUpdateItem &u2 = updateItems[*p2];↩
// NonAnti < Anti↩
if (u1.IsAnti != u2.IsAnti)↩
return (u1.IsAnti ? 1 : -1);↩
if (u1.IsDir != u2.IsDir)↩
{↩
// Dir.NonAnti < File < Dir.Anti↩
if (u1.IsDir)↩
return (u1.IsAnti ? 1 : -1);↩
return (u2.IsAnti ? -1 : 1);↩
}↩
int n = CompareFileNames(u1.Name, u2.Name);↩
return (u1.IsDir && u1.IsAnti) ? -n : n;↩
}↩
static const char *g_Exts =↩
" 7z xz lzma ace arc arj bz tbz bz2 tbz2 cab deb gz tgz ha lha lzh lzo lzx pak rar rpm sit zoo"
" zip jar ear war msi"
" 3gp avi mov mpeg mpg mpe wmv"
" aac ape fla flac la mp3 m4a mp4 ofr ogg pac ra rm rka shn swa tta wv wma wav"
" swf"
" chm hxi hxs"
" gif jpeg jpg jp2 png tiff bmp ico psd psp"
" awg ps eps cgm dxf svg vrml wmf emf ai md"
" cad dwg pps key sxi"
" max 3ds"
" iso bin nrg mdf img pdi tar cpio xpi"
" vfd vhd vud vmc vsv"
" vmdk dsk nvram vmem vmsd vmsn vmss vmtm"
" inl inc idl acf asa"
" h hpp hxx c cpp cxx m mm go swift"
" rc java cs rs pas bas vb cls ctl frm dlg def"
" f77 f f90 f95"
" asm s"
" sql manifest dep"
" mak clw csproj vcproj sln dsp dsw"
" class"
" bat cmd bash sh"
" xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml"
" awk sed hta js json php php3 php4 php5 phptml pl pm py pyo rb tcl ts vbs"
" text txt tex ans asc srt reg ini doc docx mcw dot rtf hlp xls xlr xlt xlw ppt pdf"
" sxc sxd sxi sxg sxw stc sti stw stm odt ott odg otg odp otp ods ots odf"
" abw afp cwk lwp wpd wps wpt wrf wri"
" abf afm bdf fon mgf otf pcf pfa snf ttf"
" dbf mdb nsf ntf wdb db fdb gdb"
" exe dll ocx vbx sfx sys tlb awx com obj lib out o so"
" pdb pch idb ncb opt";↩
static unsigned GetExtIndex(const char *ext)↩
{↩
unsigned extIndex = 1;↩
const char *p = g_Exts;↩
for (;;)↩
{↩
char c = *p++;↩
if (c == 0)↩
return extIndex;↩
if (c == ' ')↩
continue;↩
unsigned pos = 0;↩
for (;;)↩
{↩
char c2 = ext[pos++];↩
if (c2 == 0 && (c == 0 || c == ' '))↩
return extIndex;↩
if (c != c2)↩
break;↩
c = *p++;↩
}↩
extIndex++;↩
for (;;)↩
{↩
if (c == 0)↩
return extIndex;↩
if (c == ' ')↩
break;↩
c = *p++;↩
}↩
}↩
}↩
struct CRefItem↩
{↩
const CUpdateItem *UpdateItem;↩
UInt32 Index;↩
unsigned ExtensionPos;↩
unsigned NamePos;↩
unsigned ExtensionIndex;↩
CRefItem() {};↩
CRefItem(UInt32 index, const CUpdateItem &ui, bool sortByType):↩
UpdateItem(&ui),↩
Index(index),↩
ExtensionPos(0),↩
NamePos(0),↩
ExtensionIndex(0)↩
{↩
if (sortByType)↩
{↩
int slashPos = ui.Name.ReverseFind_PathSepar();↩
NamePos = slashPos + 1;↩
int dotPos = ui.Name.ReverseFind_Dot();↩
if (dotPos <= slashPos)↩
ExtensionPos = ui.Name.Len();↩
else
{↩
ExtensionPos = dotPos + 1;↩
if (ExtensionPos != ui.Name.Len())↩
{↩
AString s;↩
for (unsigned pos = ExtensionPos;; pos++)↩
{↩
wchar_t c = ui.Name[pos];↩
if (c >= 0x80)↩
break;↩
if (c == 0)↩
{↩
ExtensionIndex = GetExtIndex(s);↩
break;↩
}↩
s += (char)MyCharLower_Ascii((char)c);↩
}↩
}↩
}↩
}↩
}↩
};↩
struct CSortParam↩
{↩
// const CObjectVector<CTreeFolder> *TreeFolders;↩
bool SortByType;↩
};↩
/*↩
we sort files in such order:↩
- Dir.NonAnti (name sorted)↩
- alt streams↩
- Dirs↩
- Dir.Anti (reverse name sorted)↩
*/
static int CompareUpdateItems(const CRefItem *p1, const CRefItem *p2, void *param)↩
{↩
const CRefItem &a1 = *p1;↩
const CRefItem &a2 = *p2;↩
const CUpdateItem &u1 = *a1.UpdateItem;↩
const CUpdateItem &u2 = *a2.UpdateItem;↩
/*↩
if (u1.IsAltStream != u2.IsAltStream)↩
return u1.IsAltStream ? 1 : -1;↩
*/
// Actually there are no dirs that time. They were stored in other steps↩
// So that code is unused?↩
if (u1.IsDir != u2.IsDir)↩
return u1.IsDir ? 1 : -1;↩
if (u1.IsDir)↩
{↩
if (u1.IsAnti != u2.IsAnti)↩
return (u1.IsAnti ? 1 : -1);↩
int n = CompareFileNames(u1.Name, u2.Name);↩
return -n;↩
}↩
// bool sortByType = *(bool *)param;↩
const CSortParam *sortParam = (const CSortParam *)param;↩
bool sortByType = sortParam->SortByType;↩
if (sortByType)↩
{↩
RINOZ_COMP(a1.ExtensionIndex, a2.ExtensionIndex);↩
RINOZ(CompareFileNames(u1.Name.Ptr(a1.ExtensionPos), u2.Name.Ptr(a2.ExtensionPos)));↩
RINOZ(CompareFileNames(u1.Name.Ptr(a1.NamePos), u2.Name.Ptr(a2.NamePos)));↩
if (!u1.MTimeDefined && u2.MTimeDefined) return 1;↩
if (u1.MTimeDefined && !u2.MTimeDefined) return -1;↩
if (u1.MTimeDefined && u2.MTimeDefined) RINOZ_COMP(u1.MTime, u2.MTime);↩
RINOZ_COMP(u1.Size, u2.Size);↩
}↩
/*↩
int par1 = a1.UpdateItem->ParentFolderIndex;↩
int par2 = a2.UpdateItem->ParentFolderIndex;↩
const CTreeFolder &tf1 = (*sortParam->TreeFolders)[par1];↩
const CTreeFolder &tf2 = (*sortParam->TreeFolders)[par2];↩
int b1 = tf1.SortIndex, e1 = tf1.SortIndexEnd;↩
int b2 = tf2.SortIndex, e2 = tf2.SortIndexEnd;↩
if (b1 < b2)↩
{↩
if (e1 <= b2)↩
return -1;↩
// p2 in p1↩
int par = par2;↩
for (;;)↩
{↩
const CTreeFolder &tf = (*sortParam->TreeFolders)[par];↩
par = tf.Parent;↩
if (par == par1)↩
{↩
RINOZ(CompareFileNames(u1.Name, tf.Name));↩
break;↩
}↩
}↩
}↩
else if (b2 < b1)↩
{↩
if (e2 <= b1)↩
return 1;↩
// p1 in p2↩
int par = par1;↩
for (;;)↩
{↩
const CTreeFolder &tf = (*sortParam->TreeFolders)[par];↩
par = tf.Parent;↩
if (par == par2)↩
{↩
RINOZ(CompareFileNames(tf.Name, u2.Name));↩
break;↩
}↩
}↩
}↩
*/
// RINOZ_COMP(a1.UpdateItem->ParentSortIndex, a2.UpdateItem->ParentSortIndex);↩
RINOK(CompareFileNames(u1.Name, u2.Name));↩
RINOZ_COMP(a1.UpdateItem->IndexInClient, a2.UpdateItem->IndexInClient);↩
RINOZ_COMP(a1.UpdateItem->IndexInArchive, a2.UpdateItem->IndexInArchive);↩
return 0;↩
}↩
struct CSolidGroup↩
{↩
CRecordVector<UInt32> Indices;↩
CRecordVector<CFolderRepack> folderRefs;↩
};↩
static const char * const g_ExeExts[] =↩
{↩
"dll"
, "exe"
, "ocx"
, "sfx"
, "sys"
};↩
static bool IsExeExt(const wchar_t *ext)↩
{↩
for (unsigned i = 0; i < ARRAY_SIZE(g_ExeExts); i++)↩
if (StringsAreEqualNoCase_Ascii(ext, g_ExeExts[i]))↩
return true;↩
return false;↩
}↩
struct CAnalysis↩
{↩
CMyComPtr<IArchiveUpdateCallbackFile> Callback;↩
CByteBuffer Buffer;↩
bool ParseWav;↩
bool ParseExe;↩
bool ParseAll;↩
CAnalysis():↩
ParseWav(true),↩
ParseExe(false),↩
ParseAll(false)↩
{}↩
HRESULT GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode);↩
};↩
static const size_t kAnalysisBufSize = 1 << 14;↩
HRESULT CAnalysis::GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode)↩
{↩
filterMode.Id = 0;↩
filterMode.Delta = 0;↩
CFilterMode filterModeTemp = filterMode;↩
int slashPos = ui.Name.ReverseFind_PathSepar();↩
int dotPos = ui.Name.ReverseFind_Dot();↩
// if (dotPos > slashPos)↩
{↩
bool needReadFile = ParseAll;↩
bool probablyIsSameIsa = false;↩
if (!needReadFile || !Callback)↩
{↩
const wchar_t *ext;↩
if (dotPos > slashPos)↩
ext = ui.Name.Ptr(dotPos + 1);↩
else
ext = ui.Name.RightPtr(0);↩
// p7zip uses the trick to store posix attributes in high 16 bits↩
if (ui.Attrib & 0x8000)↩
{↩
unsigned st_mode = ui.Attrib >> 16;↩
// st_mode = 00111;↩
if ((st_mode & 00111) && (ui.Size >= 2048))↩
{↩
#ifndef _WIN32↩
probablyIsSameIsa = true;↩
#endif
needReadFile = true;↩
}↩
}↩
if (IsExeExt(ext))↩
{↩
needReadFile = true;↩
#ifdef _WIN32↩
probablyIsSameIsa = true;↩
needReadFile = ParseExe;↩
#endif
}↩
else if (StringsAreEqualNoCase_Ascii(ext, "wav"))↩
{↩
needReadFile = ParseWav;↩
}↩
/*↩
else if (!needReadFile && ParseUnixExt)↩
{↩
if (StringsAreEqualNoCase_Ascii(ext, "so")↩
|| StringsAreEqualNoCase_Ascii(ext, ""))↩
needReadFile = true;↩
}↩
*/
}↩
if (needReadFile && Callback)↩
{↩
if (Buffer.Size() != kAnalysisBufSize)↩
{↩
Buffer.Alloc(kAnalysisBufSize);↩
}↩
{↩
CMyComPtr<ISequentialInStream> stream;↩
HRESULT result = Callback->GetStream2(index, &stream, NUpdateNotifyOp::kAnalyze);↩
if (result == S_OK && stream)↩
{↩
size_t size = kAnalysisBufSize;↩
result = ReadStream(stream, Buffer, &size);↩
stream.Release();↩
// RINOK(Callback->SetOperationResult2(index, NUpdate::NOperationResult::kOK));↩
if (result == S_OK)↩
{↩
Bool parseRes = ParseFile(Buffer, size, &filterModeTemp);↩
if (parseRes && filterModeTemp.Delta == 0)↩
{↩
filterModeTemp.SetDelta();↩
if (filterModeTemp.Delta != 0 && filterModeTemp.Id != k_Delta)↩
{↩
if (ui.Size % filterModeTemp.Delta != 0)↩
{↩
parseRes = false;↩
}↩
}↩
}↩
if (!parseRes)↩
{↩
filterModeTemp.Id = 0;↩
filterModeTemp.Delta = 0;↩
}↩
}↩
}↩
}↩
}↩
else if ((needReadFile && !Callback) || probablyIsSameIsa)↩
{↩
#ifdef MY_CPU_X86_OR_AMD64↩
if (probablyIsSameIsa)↩
filterModeTemp.Id = k_X86;↩
#endif
}↩
}↩
filterMode = filterModeTemp;↩
return S_OK;↩
}↩
static inline void GetMethodFull(UInt64 methodID, UInt32 numStreams, CMethodFull &m)↩
{↩
m.Id = methodID;↩
m.NumStreams = numStreams;↩
}↩
static HRESULT AddBondForFilter(CCompressionMethodMode &mode)↩
{↩
for (unsigned c = 1; c < mode.Methods.Size(); c++)↩
{↩
if (!mode.IsThereBond_to_Coder(c))↩
{↩
CBond2 bond;↩
bond.OutCoder = 0;↩
bond.OutStream = 0;↩
bond.InCoder = c;↩
mode.Bonds.Add(bond);↩
return S_OK;↩
}↩
}↩
return E_INVALIDARG;↩
}↩
static HRESULT AddFilterBond(CCompressionMethodMode &mode)↩
{↩
if (!mode.Bonds.IsEmpty())↩
return AddBondForFilter(mode);↩
return S_OK;↩
}↩
static HRESULT AddBcj2Methods(CCompressionMethodMode &mode)↩
{↩
// mode.Methods[0] must be k_BCJ2 method !↩
CMethodFull m;↩
GetMethodFull(k_LZMA, 1, m);↩
m.AddProp32(NCoderPropID::kDictionarySize, 1 << 20);↩
m.AddProp32(NCoderPropID::kNumFastBytes, 128);↩
m.AddProp32(NCoderPropID::kNumThreads, 1);↩
m.AddProp32(NCoderPropID::kLitPosBits, 2);↩
m.AddProp32(NCoderPropID::kLitContextBits, 0);↩
// m.AddProp_Ascii(NCoderPropID::kMatchFinder, "BT2");↩
unsigned methodIndex = mode.Methods.Size();↩
if (mode.Bonds.IsEmpty())↩
{↩
for (unsigned i = 1; i + 1 < mode.Methods.Size(); i++)↩
{↩
CBond2 bond;↩
bond.OutCoder = i;↩
bond.OutStream = 0;↩
bond.InCoder = i + 1;↩
mode.Bonds.Add(bond);↩
}↩
}↩
mode.Methods.Add(m);↩
mode.Methods.Add(m);↩
RINOK(AddBondForFilter(mode));↩
CBond2 bond;↩
bond.OutCoder = 0;↩
bond.InCoder = methodIndex; bond.OutStream = 1; mode.Bonds.Add(bond);↩
bond.InCoder = methodIndex + 1; bond.OutStream = 2; mode.Bonds.Add(bond);↩
return S_OK;↩
}↩
static HRESULT MakeExeMethod(CCompressionMethodMode &mode,↩
const CFilterMode &filterMode, /* bool addFilter, */ bool bcj2Filter)↩
{↩
if (mode.Filter_was_Inserted)↩
{↩
const CMethodFull &m = mode.Methods[0];↩
CMethodId id = m.Id;↩
if (id == k_BCJ2)↩
return AddBcj2Methods(mode);↩
if (!m.IsSimpleCoder())↩
return E_NOTIMPL;↩
// if (Bonds.IsEmpty()) we can create bonds later↩
return AddFilterBond(mode);↩
}↩
if (filterMode.Id == 0)↩
return S_OK;↩
CMethodFull &m = mode.Methods.InsertNew(0);↩
{↩
FOR_VECTOR(k, mode.Bonds)↩
{↩
CBond2 &bond = mode.Bonds[k];↩
bond.InCoder++;↩
bond.OutCoder++;↩
}↩
}↩
HRESULT res;↩
if (bcj2Filter && Is86Filter(filterMode.Id))↩
{↩
GetMethodFull(k_BCJ2, 4, m);↩
res = AddBcj2Methods(mode);↩
}↩
else
{↩
GetMethodFull(filterMode.Id, 1, m);↩
if (filterMode.Id == k_Delta)↩
m.AddProp32(NCoderPropID::kDefaultProp, filterMode.Delta);↩
res = AddFilterBond(mode);↩
int alignBits = -1;↩
if (filterMode.Id == k_Delta || filterMode.Delta != 0)↩
{↩
if (filterMode.Delta == 1) alignBits = 0;↩
else if (filterMode.Delta == 2) alignBits = 1;↩
else if (filterMode.Delta == 4) alignBits = 2;↩
else if (filterMode.Delta == 8) alignBits = 3;↩
else if (filterMode.Delta == 16) alignBits = 4;↩
}↩
else
{↩
// alignBits = GetAlignForFilterMethod(filterMode.Id);↩
}↩
if (res == S_OK && alignBits >= 0)↩
{↩
unsigned nextCoder = 1;↩
if (!mode.Bonds.IsEmpty())↩
{↩
nextCoder = mode.Bonds.Back().InCoder;↩
}↩
if (nextCoder < mode.Methods.Size())↩
{↩
CMethodFull &nextMethod = mode.Methods[nextCoder];↩
if (nextMethod.Id == k_LZMA || nextMethod.Id == k_LZMA2)↩
{↩
if (!nextMethod.Are_Lzma_Model_Props_Defined())↩
{↩
if (alignBits != 0)↩
{↩
if (alignBits > 2 || filterMode.Id == k_Delta)↩
nextMethod.AddProp32(NCoderPropID::kPosStateBits, alignBits);↩
unsigned lc = 0;↩
if (alignBits < 3)↩
lc = 3 - alignBits;↩
nextMethod.AddProp32(NCoderPropID::kLitContextBits, lc);↩
nextMethod.AddProp32(NCoderPropID::kLitPosBits, alignBits);↩
}↩
}↩
}↩
}↩
}↩
}↩
return res;↩
}↩
static void UpdateItem_To_FileItem2(const CUpdateItem &ui, CFileItem2 &file2)↩
{↩
file2.Attrib = ui.Attrib; file2.AttribDefined = ui.AttribDefined;↩
file2.CTime = ui.CTime; file2.CTimeDefined = ui.CTimeDefined;↩
file2.ATime = ui.ATime; file2.ATimeDefined = ui.ATimeDefined;↩
file2.MTime = ui.MTime; file2.MTimeDefined = ui.MTimeDefined;↩
file2.IsAnti = ui.IsAnti;↩
// file2.IsAux = false;↩
file2.StartPosDefined = false;↩
// file2.StartPos = 0;↩
}↩
static void UpdateItem_To_FileItem(const CUpdateItem &ui,↩
CFileItem &file, CFileItem2 &file2)↩
{↩
UpdateItem_To_FileItem2(ui, file2);↩
file.Size = ui.Size;↩
file.IsDir = ui.IsDir;↩
file.HasStream = ui.HasStream();↩
// file.IsAltStream = ui.IsAltStream;↩
}↩
class CRepackInStreamWithSizes:↩
public ISequentialInStream,↩
public ICompressGetSubStreamSize,↩
public CMyUnknownImp↩
{↩
CMyComPtr<ISequentialInStream> _stream;↩
// UInt64 _size;↩
const CBoolVector *_extractStatuses;↩
UInt32 _startIndex;↩
public:↩
const CDbEx *_db;↩
void Init(ISequentialInStream *stream, UInt32 startIndex, const CBoolVector *extractStatuses)↩
{↩
_startIndex = startIndex;↩
_extractStatuses = extractStatuses;↩
// _size = 0;↩
_stream = stream;↩
}↩
// UInt64 GetSize() const { return _size; }↩
MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize)↩
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);↩
STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);↩
};↩
STDMETHODIMP CRepackInStreamWithSizes::Read(void *data, UInt32 size, UInt32 *processedSize)↩
{↩
return _stream->Read(data, size, processedSize);↩
/*↩
UInt32 realProcessedSize;↩
HRESULT result = _stream->Read(data, size, &realProcessedSize);↩
_size += realProcessedSize;↩
if (processedSize)↩
*processedSize = realProcessedSize;↩
return result;↩
*/
}↩
STDMETHODIMP CRepackInStreamWithSizes::GetSubStreamSize(UInt64 subStream, UInt64 *value)↩
{↩
*value = 0;↩
if (subStream >= _extractStatuses->Size())↩
return S_FALSE; // E_FAIL;↩
unsigned index = (unsigned)subStream;↩
if ((*_extractStatuses)[index])↩
{↩
const CFileItem &fi = _db->Files[_startIndex + index];↩
if (fi.HasStream)↩
*value = fi.Size;↩
}↩
return S_OK;↩
}↩
class CRepackStreamBase↩
{↩
protected:↩
bool _needWrite;↩
bool _fileIsOpen;↩
bool _calcCrc;↩
UInt32 _crc;↩
UInt64 _rem;↩
const CBoolVector *_extractStatuses;↩
UInt32 _startIndex;↩
unsigned _currentIndex;↩
HRESULT OpenFile();↩
HRESULT CloseFile();↩
HRESULT ProcessEmptyFiles();↩
public:↩
const CDbEx *_db;↩
CMyComPtr<IArchiveUpdateCallbackFile> _opCallback;↩
CMyComPtr<IArchiveExtractCallbackMessage> _extractCallback;↩
HRESULT Init(UInt32 startIndex, const CBoolVector *extractStatuses);↩
HRESULT CheckFinishedState() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; }↩
};↩
HRESULT CRepackStreamBase::Init(UInt32 startIndex, const CBoolVector *extractStatuses)↩
{↩
_startIndex = startIndex;↩
_extractStatuses = extractStatuses;↩
_currentIndex = 0;↩
_fileIsOpen = false;↩
return ProcessEmptyFiles();↩
}↩
HRESULT CRepackStreamBase::OpenFile()↩
{↩
UInt32 arcIndex = _startIndex + _currentIndex;↩
const CFileItem &fi = _db->Files[arcIndex];↩
_needWrite = (*_extractStatuses)[_currentIndex];↩
if (_opCallback)↩
{↩
RINOK(_opCallback->ReportOperation(↩
NEventIndexType::kInArcIndex, arcIndex,↩
_needWrite ?↩
NUpdateNotifyOp::kRepack :↩
NUpdateNotifyOp::kSkip));↩
}↩
_crc = CRC_INIT_VAL;↩
_calcCrc = (fi.CrcDefined && !fi.IsDir);↩
_fileIsOpen = true;↩
_rem = fi.Size;↩
return S_OK;↩
}↩
const HRESULT k_My_HRESULT_CRC_ERROR = 0x20000002;↩
HRESULT CRepackStreamBase::CloseFile()↩
{↩
UInt32 arcIndex = _startIndex + _currentIndex;↩
const CFileItem &fi = _db->Files[arcIndex];↩
_fileIsOpen = false;↩
_currentIndex++;↩
if (!_calcCrc || fi.Crc == CRC_GET_DIGEST(_crc))↩
return S_OK;↩
if (_extractCallback)↩
{↩
RINOK(_extractCallback->ReportExtractResult(↩
NEventIndexType::kInArcIndex, arcIndex,↩
NExtract::NOperationResult::kCRCError));↩
}↩
// return S_FALSE;↩
return k_My_HRESULT_CRC_ERROR;↩
}↩
HRESULT CRepackStreamBase::ProcessEmptyFiles()↩
{↩
while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0)↩
{↩
RINOK(OpenFile());↩
RINOK(CloseFile());↩
}↩
return S_OK;↩
}↩
#ifndef _7ZIP_ST↩
class CFolderOutStream2:↩
public CRepackStreamBase,↩
public ISequentialOutStream,↩
public CMyUnknownImp↩
{↩
public:↩
CMyComPtr<ISequentialOutStream> _stream;↩
MY_UNKNOWN_IMP↩
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);↩
};↩
STDMETHODIMP CFolderOutStream2::Write(const void *data, UInt32 size, UInt32 *processedSize)↩
{↩
if (processedSize)↩
*processedSize = 0;↩
while (size != 0)↩
{↩
if (_fileIsOpen)↩
{↩
UInt32 cur = (size < _rem ? size : (UInt32)_rem);↩
HRESULT result = S_OK;↩
if (_needWrite)↩
result = _stream->Write(data, cur, &cur);↩
if (_calcCrc)↩
_crc = CrcUpdate(_crc, data, cur);↩
if (processedSize)↩
*processedSize += cur;↩
data = (const Byte *)data + cur;↩
size -= cur;↩
_rem -= cur;↩
if (_rem == 0)↩
{↩
RINOK(CloseFile());↩
RINOK(ProcessEmptyFiles());↩
}↩
RINOK(result);↩
if (cur == 0)↩
break;↩
continue;↩
}↩
RINOK(ProcessEmptyFiles());↩
if (_currentIndex == _extractStatuses->Size())↩
{↩
// we don't support write cut here↩
return E_FAIL;↩
}↩
RINOK(OpenFile());↩
}↩
return S_OK;↩
}↩
#endif
static const UInt32 kTempBufSize = 1 << 16;↩
class CFolderInStream2:↩
public CRepackStreamBase,↩
public ISequentialInStream,↩
public CMyUnknownImp↩
{↩
Byte *_buf;↩
public:↩
CMyComPtr<ISequentialInStream> _inStream;↩
HRESULT Result;↩
MY_UNKNOWN_IMP↩
CFolderInStream2():↩
Result(S_OK)↩
{↩
_buf = new Byte[kTempBufSize];↩
}↩
~CFolderInStream2()↩
{↩
delete []_buf;↩
}↩
void Init() { Result = S_OK; }↩
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);↩
};↩
STDMETHODIMP CFolderInStream2::Read(void *data, UInt32 size, UInt32 *processedSize)↩
{↩
if (processedSize)↩
*processedSize = 0;↩
while (size != 0)↩
{↩
if (_fileIsOpen)↩
{↩
UInt32 cur = (size < _rem ? size : (UInt32)_rem);↩
void *buf;↩
if (_needWrite)↩
buf = data;↩
else
{↩
buf = _buf;↩
if (cur > kTempBufSize)↩
cur = kTempBufSize;↩
}↩
HRESULT result = _inStream->Read(buf, cur, &cur);↩
_crc = CrcUpdate(_crc, buf, cur);↩
_rem -= cur;↩
if (_needWrite)↩
{↩
data = (Byte *)data + cur;↩
size -= cur;↩
if (processedSize)↩
*processedSize += cur;↩
}↩
if (result != S_OK)↩
Result = result;↩
if (_rem == 0)↩
{↩
RINOK(CloseFile());↩
RINOK(ProcessEmptyFiles());↩
}↩
RINOK(result);↩
if (cur == 0)↩
return E_FAIL;↩
continue;↩
}↩
RINOK(ProcessEmptyFiles());↩
if (_currentIndex == _extractStatuses->Size())↩
{↩
return S_OK;↩
}↩
RINOK(OpenFile());↩
}↩
return S_OK;↩
}↩
class CThreadDecoder↩
#ifndef _7ZIP_ST↩
: public CVirtThread↩
#endif
{↩
public:↩
CDecoder Decoder;↩
CThreadDecoder(bool multiThreadMixer):↩
Decoder(multiThreadMixer)↩
{↩
#ifndef _7ZIP_ST↩
if (multiThreadMixer)↩
{↩
MtMode = false;↩
NumThreads = 1;↩
FosSpec = new CFolderOutStream2;↩
Fos = FosSpec;↩
Result = E_FAIL;↩
}↩
#endif
// UnpackSize = 0;↩
// send_UnpackSize = false;↩
}↩
#ifndef _7ZIP_ST↩
bool dataAfterEnd_Error;↩
HRESULT Result;↩
CMyComPtr<IInStream> InStream;↩
CFolderOutStream2 *FosSpec;↩
CMyComPtr<ISequentialOutStream> Fos;↩
UInt64 StartPos;↩
const CFolders *Folders;↩
int FolderIndex;↩
// bool send_UnpackSize;↩
// UInt64 UnpackSize;↩
#ifndef _NO_CRYPTO↩
CMyComPtr<ICryptoGetTextPassword> getTextPassword;↩
#endif
DECL_EXTERNAL_CODECS_LOC_VARS2;↩
#ifndef _7ZIP_ST↩
bool MtMode;↩
UInt32 NumThreads;↩
#endif
~CThreadDecoder() { CVirtThread::WaitThreadFinish(); }↩
virtual void Execute();↩
#endif
};↩
#ifndef _7ZIP_ST↩
void CThreadDecoder::Execute()↩
{↩
try
{↩
#ifndef _NO_CRYPTO↩
bool isEncrypted = false;↩
bool passwordIsDefined = false;↩
UString password;↩
#endif
dataAfterEnd_Error = false;↩
Result = Decoder.Decode(↩
EXTERNAL_CODECS_LOC_VARS↩
InStream,↩
StartPos,↩
*Folders, FolderIndex,↩
// send_UnpackSize ? &UnpackSize : NULL,↩
NULL, // unpackSize : FULL unpack↩
Fos,↩
NULL, // compressProgress↩
NULL // *inStreamMainRes↩
, dataAfterEnd_Error↩
_7Z_DECODER_CRYPRO_VARS↩
#ifndef _7ZIP_ST↩
, MtMode, NumThreads,↩
0 // MemUsage↩
#endif
);↩
}↩
catch(...)↩
{↩
Result = E_FAIL;↩
}↩
/*↩
if (Result == S_OK)↩
Result = FosSpec->CheckFinishedState();↩
*/
FosSpec->_stream.Release();↩
}↩
#endif
#ifndef _NO_CRYPTO↩
class CCryptoGetTextPassword:↩
public ICryptoGetTextPassword,↩
public CMyUnknownImp↩
{↩
public:↩
UString Password;↩
MY_UNKNOWN_IMP↩
STDMETHOD(CryptoGetTextPassword)(BSTR *password);↩
};↩
STDMETHODIMP CCryptoGetTextPassword::CryptoGetTextPassword(BSTR *password)↩
{↩
return StringToBstr(Password, password);↩
}↩
#endif
static void GetFile(const CDatabase &inDb, unsigned index, CFileItem &file, CFileItem2 &file2)↩
{↩
file = inDb.Files[index];↩
file2.CTimeDefined = inDb.CTime.GetItem(index, file2.CTime);↩
file2.ATimeDefined = inDb.ATime.GetItem(index, file2.ATime);↩
file2.MTimeDefined = inDb.MTime.GetItem(index, file2.MTime);↩
file2.StartPosDefined = inDb.StartPos.GetItem(index, file2.StartPos);↩
file2.AttribDefined = inDb.Attrib.GetItem(index, file2.Attrib);↩
file2.IsAnti = inDb.IsItemAnti(index);↩
// file2.IsAux = inDb.IsItemAux(index);↩
}↩
HRESULT Update(↩
DECL_EXTERNAL_CODECS_LOC_VARS↩
IInStream *inStream,↩
const CDbEx *db,↩
const CObjectVector<CUpdateItem> &updateItems,↩
// const CObjectVector<CTreeFolder> &treeFolders,↩
// const CUniqBlocks &secureBlocks,↩
COutArchive &archive,↩
CArchiveDatabaseOut &newDatabase,↩
ISequentialOutStream *seqOutStream,↩
IArchiveUpdateCallback *updateCallback,↩
const CUpdateOptions &options↩
#ifndef _NO_CRYPTO↩
, ICryptoGetTextPassword *getDecoderPassword↩
#endif
)↩
{↩
UInt64 numSolidFiles = options.NumSolidFiles;↩
if (numSolidFiles == 0)↩
numSolidFiles = 1;↩
CMyComPtr<IArchiveUpdateCallbackFile> opCallback;↩
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);↩
CMyComPtr<IArchiveExtractCallbackMessage> extractCallback;↩
updateCallback->QueryInterface(IID_IArchiveExtractCallbackMessage, (void **)&extractCallback);↩
// size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes();↩
/*↩
CMyComPtr<IOutStream> outStream;↩
RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream));↩
if (!outStream)↩
return E_NOTIMPL;↩
*/
UInt64 startBlockSize = db ? db->ArcInfo.StartPosition: 0;↩
if (startBlockSize > 0 && !options.RemoveSfxBlock)↩
{↩
RINOK(WriteRange(inStream, seqOutStream, 0, startBlockSize, NULL));↩
}↩
CIntArr fileIndexToUpdateIndexMap;↩
UInt64 complexity = 0;↩
UInt64 inSizeForReduce2 = 0;↩
bool needEncryptedRepack = false;↩
CRecordVector<CFilterMode2> filters;↩
CObjectVector<CSolidGroup> groups;↩
bool thereAreRepacks = false;↩
bool useFilters = options.UseFilters;↩
if (useFilters)↩
{↩
const CCompressionMethodMode &method = *options.Method;↩
FOR_VECTOR (i, method.Methods)↩
if (IsFilterMethod(method.Methods[i].Id))↩
{↩
useFilters = false;↩
break;↩
}↩
}↩
if (db)↩
{↩
fileIndexToUpdateIndexMap.Alloc(db->Files.Size());↩
unsigned i;↩
for (i = 0; i < db->Files.Size(); i++)↩
fileIndexToUpdateIndexMap[i] = -1;↩
for (i = 0; i < updateItems.Size(); i++)↩
{↩
int index = updateItems[i].IndexInArchive;↩
if (index != -1)↩
fileIndexToUpdateIndexMap[(unsigned)index] = i;↩
}↩
for (i = 0; i < db->NumFolders; i++)↩
{↩
CNum indexInFolder = 0;↩
CNum numCopyItems = 0;↩
CNum numUnpackStreams = db->NumUnpackStreamsVector[i];↩
UInt64 repackSize = 0;↩
for (CNum fi = db->FolderStartFileIndex[i]; indexInFolder < numUnpackStreams; fi++)↩
{↩
const CFileItem &file = db->Files[fi];↩
if (file.HasStream)↩
{↩
indexInFolder++;↩
int updateIndex = fileIndexToUpdateIndexMap[fi];↩
if (updateIndex >= 0 && !updateItems[updateIndex].NewData)↩
{↩
numCopyItems++;↩
repackSize += file.Size;↩
}↩
}↩
}↩
if (numCopyItems == 0)↩
continue;↩
CFolderRepack rep;↩
rep.FolderIndex = i;↩
rep.NumCopyFiles = numCopyItems;↩
CFolderEx f;↩
db->ParseFolderEx(i, f);↩
const bool isEncrypted = f.IsEncrypted();↩
const bool needCopy = (numCopyItems == numUnpackStreams);↩
const bool extractFilter = (useFilters || needCopy);↩
unsigned groupIndex = Get_FilterGroup_for_Folder(filters, f, extractFilter);↩
while (groupIndex >= groups.Size())↩
groups.AddNew();↩
groups[groupIndex].folderRefs.Add(rep);↩
if (needCopy)↩
complexity += db->GetFolderFullPackSize(i);↩
else
{↩
thereAreRepacks = true;↩
complexity += repackSize;↩
if (inSizeForReduce2 < repackSize)↩
inSizeForReduce2 = repackSize;↩
if (isEncrypted)↩
needEncryptedRepack = true;↩
}↩
}↩
}↩
UInt64 inSizeForReduce = 0;↩
{↩
bool isSolid = (numSolidFiles > 1 && options.NumSolidBytes != 0);↩
FOR_VECTOR (i, updateItems)↩
{↩
const CUpdateItem &ui = updateItems[i];↩
if (ui.NewData)↩
{↩
complexity += ui.Size;↩
if (isSolid)↩
inSizeForReduce += ui.Size;↩
else if (inSizeForReduce < ui.Size)↩
inSizeForReduce = ui.Size;↩
}↩
}↩
}↩
if (inSizeForReduce < inSizeForReduce2)↩
inSizeForReduce = inSizeForReduce2;↩
RINOK(updateCallback->SetTotal(complexity));↩
CLocalProgress *lps = new CLocalProgress;↩
CMyComPtr<ICompressProgressInfo> progress = lps;↩
lps->Init(updateCallback, true);↩
#ifndef _7ZIP_ST↩
CStreamBinder sb;↩
if (options.MultiThreadMixer)↩
{↩
RINOK(sb.CreateEvents());↩
}↩
#endif
CThreadDecoder threadDecoder(options.MultiThreadMixer);↩
#ifndef _7ZIP_ST↩
if (options.MultiThreadMixer && thereAreRepacks)↩
{↩
#ifdef EXTERNAL_CODECS↩
threadDecoder.__externalCodecs = __externalCodecs;↩
#endif
RINOK(threadDecoder.Create());↩
}↩
#endif
{↩
CAnalysis analysis;↩
if (options.AnalysisLevel == 0)↩
{↩
analysis.ParseWav = false;↩
analysis.ParseExe = false;↩
analysis.ParseAll = false;↩
}↩
else
{↩
analysis.Callback = opCallback;↩
if (options.AnalysisLevel > 0)↩
{↩
analysis.ParseWav = true;↩
if (options.AnalysisLevel >= 7)↩
{↩
analysis.ParseExe = true;↩
if (options.AnalysisLevel >= 9)↩
analysis.ParseAll = true;↩
}↩
}↩
}↩
// ---------- Split files to groups ----------↩
const CCompressionMethodMode &method = *options.Method;↩
FOR_VECTOR (i, updateItems)↩
{↩
const CUpdateItem &ui = updateItems[i];↩
if (!ui.NewData || !ui.HasStream())↩
continue;↩
CFilterMode2 fm;↩
if (useFilters)↩
{↩
RINOK(analysis.GetFilterGroup(i, ui, fm));↩
}↩
fm.Encrypted = method.PasswordIsDefined;↩
unsigned groupIndex = GetGroup(filters, fm);↩
while (groupIndex >= groups.Size())↩
groups.AddNew();↩
groups[groupIndex].Indices.Add(i);↩
}↩
}↩
#ifndef _NO_CRYPTO↩
CCryptoGetTextPassword *getPasswordSpec = NULL;↩
CMyComPtr<ICryptoGetTextPassword> getTextPassword;↩
if (needEncryptedRepack)↩
{↩
getPasswordSpec = new CCryptoGetTextPassword;↩
getTextPassword = getPasswordSpec;↩
#ifndef _7ZIP_ST↩
threadDecoder.getTextPassword = getPasswordSpec;↩
#endif
if (options.Method->PasswordIsDefined)↩
getPasswordSpec->Password = options.Method->Password;↩
else
{↩
if (!getDecoderPassword)↩
return E_NOTIMPL;↩
CMyComBSTR password;↩
RINOK(getDecoderPassword->CryptoGetTextPassword(&password));↩
if (password)↩
getPasswordSpec->Password = password;↩
}↩
}↩
#endif
// ---------- Compress ----------↩
RINOK(archive.Create(seqOutStream, false));↩
RINOK(archive.SkipPrefixArchiveHeader());↩
/*↩
CIntVector treeFolderToArcIndex;↩
treeFolderToArcIndex.Reserve(treeFolders.Size());↩
for (i = 0; i < treeFolders.Size(); i++)↩
treeFolderToArcIndex.Add(-1);↩
// ---------- Write Tree (only AUX dirs) ----------↩
for (i = 1; i < treeFolders.Size(); i++)↩
{↩
const CTreeFolder &treeFolder = treeFolders[i];↩
CFileItem file;↩
CFileItem2 file2;↩
file2.Init();↩
int secureID = 0;↩
if (treeFolder.UpdateItemIndex < 0)↩
{↩
// we can store virtual dir item wuthout attrib, but we want all items have attrib.↩
file.SetAttrib(FILE_ATTRIBUTE_DIRECTORY);↩
file2.IsAux = true;↩
}↩
else↩
{↩
const CUpdateItem &ui = updateItems[treeFolder.UpdateItemIndex];↩
// if item is not dir, then it's parent for alt streams.↩
// we will write such items later↩
if (!ui.IsDir)↩
continue;↩
secureID = ui.SecureIndex;↩
if (ui.NewProps)↩
UpdateItem_To_FileItem(ui, file, file2);↩
else↩
GetFile(*db, ui.IndexInArchive, file, file2);↩
}↩
file.Size = 0;↩
file.HasStream = false;↩
file.IsDir = true;↩
file.Parent = treeFolder.Parent;↩
treeFolderToArcIndex[i] = newDatabase.Files.Size();↩
newDatabase.AddFile(file, file2, treeFolder.Name);↩
if (totalSecureDataSize != 0)↩
newDatabase.SecureIDs.Add(secureID);↩
}↩
*/
{↩
/* ---------- Write non-AUX dirs and Empty files ---------- */
CUIntVector emptyRefs;↩
unsigned i;↩
for (i = 0; i < updateItems.Size(); i++)↩
{↩
const CUpdateItem &ui = updateItems[i];↩
if (ui.NewData)↩
{↩
if (ui.HasStream())↩
continue;↩
}↩
else if (ui.IndexInArchive != -1 && db->Files[ui.IndexInArchive].HasStream)↩
continue;↩
/*↩
if (ui.TreeFolderIndex >= 0)↩
continue;↩
*/
emptyRefs.Add(i);↩
}↩
emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems);↩
for (i = 0; i < emptyRefs.Size(); i++)↩
{↩
const CUpdateItem &ui = updateItems[emptyRefs[i]];↩
CFileItem file;↩
CFileItem2 file2;↩
UString name;↩
if (ui.NewProps)↩
{↩
UpdateItem_To_FileItem(ui, file, file2);↩
file.CrcDefined = false;↩
name = ui.Name;↩
}↩
else
{↩
GetFile(*db, ui.IndexInArchive, file, file2);↩
db->GetPath(ui.IndexInArchive, name);↩
}↩
/*↩
if (totalSecureDataSize != 0)↩
newDatabase.SecureIDs.Add(ui.SecureIndex);↩
file.Parent = ui.ParentFolderIndex;↩
*/
newDatabase.AddFile(file, file2, name);↩
}↩
}↩
lps->ProgressOffset = 0;↩
{↩
// ---------- Sort Filters ----------↩
FOR_VECTOR (i, filters)↩
{↩
filters[i].GroupIndex = i;↩
}↩
filters.Sort2();↩
}↩
for (unsigned groupIndex = 0; groupIndex < filters.Size(); groupIndex++)↩
{↩
const CFilterMode2 &filterMode = filters[groupIndex];↩
CCompressionMethodMode method = *options.Method;↩
{↩
HRESULT res = MakeExeMethod(method, filterMode,↩
#ifdef _7ZIP_ST↩
false
#else
options.MaxFilter && options.MultiThreadMixer↩
#endif
);↩
RINOK(res);↩
}↩
if (filterMode.Encrypted)↩
{↩
if (!method.PasswordIsDefined)↩
{↩
#ifndef _NO_CRYPTO↩
if (getPasswordSpec)↩
method.Password = getPasswordSpec->Password;↩
#endif
method.PasswordIsDefined = true;↩
}↩
}↩
else
{↩
method.PasswordIsDefined = false;↩
method.Password.Empty();↩
}↩
CEncoder encoder(method);↩
// ---------- Repack and copy old solid blocks ----------↩
const CSolidGroup &group = groups[filterMode.GroupIndex];↩
FOR_VECTOR(folderRefIndex, group.folderRefs)↩
{↩
const CFolderRepack &rep = group.folderRefs[folderRefIndex];↩
unsigned folderIndex = rep.FolderIndex;↩
CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex];↩
if (rep.NumCopyFiles == numUnpackStreams)↩
{↩
if (opCallback)↩
{↩
RINOK(opCallback->ReportOperation(↩
NEventIndexType::kBlockIndex, (UInt32)folderIndex,↩
NUpdateNotifyOp::kReplicate));↩
// ---------- Copy old solid block ----------↩
{↩
CNum indexInFolder = 0;↩
for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++)↩
{↩
if (db->Files[fi].HasStream)↩
{↩
indexInFolder++;↩
RINOK(opCallback->ReportOperation(↩
NEventIndexType::kInArcIndex, (UInt32)fi,↩
NUpdateNotifyOp::kReplicate));↩
}↩
}↩
}↩
}↩
UInt64 packSize = db->GetFolderFullPackSize(folderIndex);↩
RINOK(WriteRange(inStream, archive.SeqStream,↩
db->GetFolderStreamPos(folderIndex, 0), packSize, progress));↩
lps->ProgressOffset += packSize;↩
CFolder &folder = newDatabase.Folders.AddNew();↩
db->ParseFolderInfo(folderIndex, folder);↩
CNum startIndex = db->FoStartPackStreamIndex[folderIndex];↩
FOR_VECTOR(j, folder.PackStreams)↩
{↩
newDatabase.PackSizes.Add(db->GetStreamPackSize(startIndex + j));↩
// newDatabase.PackCRCsDefined.Add(db.PackCRCsDefined[startIndex + j]);↩
// newDatabase.PackCRCs.Add(db.PackCRCs[startIndex + j]);↩
}↩
size_t indexStart = db->FoToCoderUnpackSizes[folderIndex];↩
size_t indexEnd = db->FoToCoderUnpackSizes[folderIndex + 1];↩
for (; indexStart < indexEnd; indexStart++)↩
newDatabase.CoderUnpackSizes.Add(db->CoderUnpackSizes[indexStart]);↩
}↩
else
{↩
// ---------- Repack old solid block ----------↩
CBoolVector extractStatuses;↩
CNum indexInFolder = 0;↩
if (opCallback)↩
{↩
RINOK(opCallback->ReportOperation(↩
NEventIndexType::kBlockIndex, (UInt32)folderIndex,↩
NUpdateNotifyOp::kRepack))↩
}↩
/* We could reduce data size of decoded folder, if we don't need to repack↩
last files in folder. But the gain in speed is small in most cases.↩
So we unpack full folder. */
UInt64 sizeToEncode = 0;↩
/*↩
UInt64 importantUnpackSize = 0;↩
unsigned numImportantFiles = 0;↩
UInt64 decodeSize = 0;↩
*/
for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++)↩
{↩
bool needExtract = false;↩
const CFileItem &file = db->Files[fi];↩
if (file.HasStream)↩
{↩
indexInFolder++;↩
int updateIndex = fileIndexToUpdateIndexMap[fi];↩
if (updateIndex >= 0 && !updateItems[updateIndex].NewData)↩
needExtract = true;↩
// decodeSize += file.Size;↩
}↩
extractStatuses.Add(needExtract);↩
if (needExtract)↩
{↩
sizeToEncode += file.Size;↩
/*↩
numImportantFiles = extractStatuses.Size();↩
importantUnpackSize = decodeSize;↩
*/
}↩
}↩
// extractStatuses.DeleteFrom(numImportantFiles);↩
unsigned startPackIndex = newDatabase.PackSizes.Size();↩
UInt64 curUnpackSize;↩
{↩
CMyComPtr<ISequentialInStream> sbInStream;↩
CRepackStreamBase *repackBase;↩
CFolderInStream2 *FosSpec2 = NULL;↩
CRepackInStreamWithSizes *inStreamSizeCountSpec = new CRepackInStreamWithSizes;↩
CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;↩
{↩
#ifndef _7ZIP_ST↩
if (options.MultiThreadMixer)↩
{↩
repackBase = threadDecoder.FosSpec;↩
CMyComPtr<ISequentialOutStream> sbOutStream;↩
sb.CreateStreams(&sbInStream, &sbOutStream);↩
sb.ReInit();↩
threadDecoder.FosSpec->_stream = sbOutStream;↩
threadDecoder.InStream = inStream;↩
threadDecoder.StartPos = db->ArcInfo.DataStartPosition; // db->GetFolderStreamPos(folderIndex, 0);↩
threadDecoder.Folders = (const CFolders *)db;↩
threadDecoder.FolderIndex = folderIndex;↩
// threadDecoder.UnpackSize = importantUnpackSize;↩
// threadDecoder.send_UnpackSize = true;↩
}↩
else
#endif
{↩
FosSpec2 = new CFolderInStream2;↩
FosSpec2->Init();↩
sbInStream = FosSpec2;↩
repackBase = FosSpec2;↩
#ifndef _NO_CRYPTO↩
bool isEncrypted = false;↩
bool passwordIsDefined = false;↩
UString password;↩
#endif
CMyComPtr<ISequentialInStream> decodedStream;↩
bool dataAfterEnd_Error = false;↩
HRESULT res = threadDecoder.Decoder.Decode(↩
EXTERNAL_CODECS_LOC_VARS↩
inStream,↩
db->ArcInfo.DataStartPosition, // db->GetFolderStreamPos(folderIndex, 0);,↩
*db, folderIndex,↩
// &importantUnpackSize, // *unpackSize↩
NULL, // *unpackSize : FULL unpack↩
NULL, // *outStream↩
NULL, // *compressProgress↩
&decodedStream↩
, dataAfterEnd_Error↩
_7Z_DECODER_CRYPRO_VARS↩
#ifndef _7ZIP_ST↩
, false // mtMode↩
, 1 // numThreads↩
, 0 // memUsage↩
#endif
);↩
RINOK(res);↩
if (!decodedStream)↩
return E_FAIL;↩
FosSpec2->_inStream = decodedStream;↩
}↩
repackBase->_db = db;↩
repackBase->_opCallback = opCallback;↩
repackBase->_extractCallback = extractCallback;↩
UInt32 startIndex = db->FolderStartFileIndex[folderIndex];↩
RINOK(repackBase->Init(startIndex, &extractStatuses));↩
inStreamSizeCountSpec->_db = db;↩
inStreamSizeCountSpec->Init(sbInStream, startIndex, &extractStatuses);↩
#ifndef _7ZIP_ST↩
if (options.MultiThreadMixer)↩
{↩
threadDecoder.Start();↩
}↩
#endif
}↩
curUnpackSize = sizeToEncode;↩
HRESULT encodeRes = encoder.Encode(↩
EXTERNAL_CODECS_LOC_VARS↩
inStreamSizeCount,↩
// NULL,↩
&inSizeForReduce,↩
newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curUnpackSize,↩
archive.SeqStream, newDatabase.PackSizes, progress);↩
if (encodeRes == k_My_HRESULT_CRC_ERROR)↩
return E_FAIL;↩
#ifndef _7ZIP_ST↩
if (options.MultiThreadMixer)↩
{↩
// 16.00: hang was fixed : for case if decoding was not finished.↩
// We close CBinderInStream and it calls CStreamBinder::CloseRead()↩
inStreamSizeCount.Release();↩
sbInStream.Release();↩
threadDecoder.WaitExecuteFinish();↩
HRESULT decodeRes = threadDecoder.Result;↩
// if (res == k_My_HRESULT_CRC_ERROR)↩
if (decodeRes == S_FALSE || threadDecoder.dataAfterEnd_Error)↩
{↩
if (extractCallback)↩
{↩
RINOK(extractCallback->ReportExtractResult(↩
NEventIndexType::kInArcIndex, db->FolderStartFileIndex[folderIndex],↩
// NEventIndexType::kBlockIndex, (UInt32)folderIndex,↩
(decodeRes != S_OK ?↩
NExtract::NOperationResult::kDataError :↩
NExtract::NOperationResult::kDataAfterEnd)));↩
}↩
if (decodeRes != S_OK)↩
return E_FAIL;↩
}↩
RINOK(decodeRes);↩
if (encodeRes == S_OK)↩
if (sb.ProcessedSize != sizeToEncode)↩
encodeRes = E_FAIL;↩
}↩
else
#endif
{↩
if (FosSpec2->Result == S_FALSE)↩
{↩
if (extractCallback)↩
{↩
RINOK(extractCallback->ReportExtractResult(↩
NEventIndexType::kBlockIndex, (UInt32)folderIndex,↩
NExtract::NOperationResult::kDataError));↩
}↩
return E_FAIL;↩
}↩
RINOK(FosSpec2->Result);↩
}↩
RINOK(encodeRes);↩
RINOK(repackBase->CheckFinishedState());↩
if (curUnpackSize != sizeToEncode)↩
return E_FAIL;↩
}↩
for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)↩
lps->OutSize += newDatabase.PackSizes[startPackIndex];↩
lps->InSize += curUnpackSize;↩
}↩
newDatabase.NumUnpackStreamsVector.Add(rep.NumCopyFiles);↩
CNum indexInFolder = 0;↩
for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++)↩
{↩
if (db->Files[fi].HasStream)↩
{↩
indexInFolder++;↩
int updateIndex = fileIndexToUpdateIndexMap[fi];↩
if (updateIndex >= 0)↩
{↩
const CUpdateItem &ui = updateItems[updateIndex];↩
if (ui.NewData)↩
continue;↩
UString name;↩
CFileItem file;↩
CFileItem2 file2;↩
GetFile(*db, fi, file, file2);↩
if (ui.NewProps)↩
{↩
UpdateItem_To_FileItem2(ui, file2);↩
file.IsDir = ui.IsDir;↩
name = ui.Name;↩
}↩
else
db->GetPath(fi, name);↩
/*↩
file.Parent = ui.ParentFolderIndex;↩
if (ui.TreeFolderIndex >= 0)↩
treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size();↩
if (totalSecureDataSize != 0)↩
newDatabase.SecureIDs.Add(ui.SecureIndex);↩
*/
newDatabase.AddFile(file, file2, name);↩
}↩
}↩
}↩
}↩
// ---------- Compress files to new solid blocks ----------↩
unsigned numFiles = group.Indices.Size();↩
if (numFiles == 0)↩
continue;↩
CRecordVector<CRefItem> refItems;↩
refItems.ClearAndSetSize(numFiles);↩
// bool sortByType = (options.UseTypeSorting && isSoid); // numSolidFiles > 1↩
bool sortByType = options.UseTypeSorting;↩
unsigned i;↩
for (i = 0; i < numFiles; i++)↩
refItems[i] = CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType);↩
CSortParam sortParam;↩
// sortParam.TreeFolders = &treeFolders;↩
sortParam.SortByType = sortByType;↩
refItems.Sort(CompareUpdateItems, (void *)&sortParam);↩
CObjArray<UInt32> indices(numFiles);↩
for (i = 0; i < numFiles; i++)↩
{↩
UInt32 index = refItems[i].Index;↩
indices[i] = index;↩
/*↩
const CUpdateItem &ui = updateItems[index];↩
CFileItem file;↩
if (ui.NewProps)↩
UpdateItem_To_FileItem(ui, file);↩
else↩
file = db.Files[ui.IndexInArchive];↩
if (file.IsAnti || file.IsDir)↩
return E_FAIL;↩
newDatabase.Files.Add(file);↩
*/
}↩
for (i = 0; i < numFiles;)↩
{↩
UInt64 totalSize = 0;↩
unsigned numSubFiles;↩
const wchar_t *prevExtension = NULL;↩
for (numSubFiles = 0; i + numSubFiles < numFiles && numSubFiles < numSolidFiles; numSubFiles++)↩
{↩
const CUpdateItem &ui = updateItems[indices[i + numSubFiles]];↩
totalSize += ui.Size;↩
if (totalSize > options.NumSolidBytes)↩
break;↩
if (options.SolidExtension)↩
{↩
int slashPos = ui.Name.ReverseFind_PathSepar();↩
int dotPos = ui.Name.ReverseFind_Dot();↩
const wchar_t *ext = ui.Name.Ptr(dotPos <= slashPos ? ui.Name.Len() : dotPos + 1);↩
if (numSubFiles == 0)↩
prevExtension = ext;↩
else if (!StringsAreEqualNoCase(ext, prevExtension))↩
break;↩
}↩
}↩
if (numSubFiles < 1)↩
numSubFiles = 1;↩
RINOK(lps->SetCur());↩
CFolderInStream *inStreamSpec = new CFolderInStream;↩
CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec);↩
inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);↩
unsigned startPackIndex = newDatabase.PackSizes.Size();↩
UInt64 curFolderUnpackSize = totalSize;↩
// curFolderUnpackSize = (UInt64)(Int64)-1;↩
RINOK(encoder.Encode(↩
EXTERNAL_CODECS_LOC_VARS↩
solidInStream,↩
// NULL,↩
&inSizeForReduce,↩
newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curFolderUnpackSize,↩
archive.SeqStream, newDatabase.PackSizes, progress));↩
if (!inStreamSpec->WasFinished())↩
return E_FAIL;↩
for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)↩
lps->OutSize += newDatabase.PackSizes[startPackIndex];↩
lps->InSize += curFolderUnpackSize;↩
// for ()↩
// newDatabase.PackCRCsDefined.Add(false);↩
// newDatabase.PackCRCs.Add(0);↩
CNum numUnpackStreams = 0;↩
UInt64 skippedSize = 0;↩
for (unsigned subIndex = 0; subIndex < numSubFiles; subIndex++)↩
{↩
const CUpdateItem &ui = updateItems[indices[i + subIndex]];↩
CFileItem file;↩
CFileItem2 file2;↩
UString name;↩
if (ui.NewProps)↩
{↩
UpdateItem_To_FileItem(ui, file, file2);↩
name = ui.Name;↩
}↩
else
{↩
GetFile(*db, ui.IndexInArchive, file, file2);↩
db->GetPath(ui.IndexInArchive, name);↩
}↩
if (file2.IsAnti || file.IsDir)↩
return E_FAIL;↩
/*↩
CFileItem &file = newDatabase.Files[↩
startFileIndexInDatabase + i + subIndex];↩
*/
if (!inStreamSpec->Processed[subIndex])↩
{↩
skippedSize += ui.Size;↩
continue;↩
// file.Name += ".locked";↩
}↩
file.Crc = inStreamSpec->CRCs[subIndex];↩
file.Size = inStreamSpec->Sizes[subIndex];↩
// if (file.Size >= 0) // test purposes↩
if (file.Size != 0)↩
{↩
file.CrcDefined = true;↩
file.HasStream = true;↩
numUnpackStreams++;↩
}↩
else
{↩
file.CrcDefined = false;↩
file.HasStream = false;↩
}↩
/*↩
file.Parent = ui.ParentFolderIndex;↩
if (ui.TreeFolderIndex >= 0)↩
treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size();↩
if (totalSecureDataSize != 0)↩
newDatabase.SecureIDs.Add(ui.SecureIndex);↩
*/
newDatabase.AddFile(file, file2, name);↩
}↩
// numUnpackStreams = 0 is very bad case for locked files↩
// v3.13 doesn't understand it.↩
newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams);↩
i += numSubFiles;↩
if (skippedSize != 0 && complexity >= skippedSize)↩
{↩
complexity -= skippedSize;↩
RINOK(updateCallback->SetTotal(complexity));↩
}↩
}↩
}↩
RINOK(lps->SetCur());↩
/*↩
fileIndexToUpdateIndexMap.ClearAndFree();↩
groups.ClearAndFree();↩
*/
/*↩
for (i = 0; i < newDatabase.Files.Size(); i++)↩
{↩
CFileItem &file = newDatabase.Files[i];↩
file.Parent = treeFolderToArcIndex[file.Parent];↩
}↩
if (totalSecureDataSize != 0)↩
{↩
newDatabase.SecureBuf.SetCapacity(totalSecureDataSize);↩
size_t pos = 0;↩
newDatabase.SecureSizes.Reserve(secureBlocks.Sorted.Size());↩
for (i = 0; i < secureBlocks.Sorted.Size(); i++)↩
{↩
const CByteBuffer &buf = secureBlocks.Bufs[secureBlocks.Sorted[i]];↩
size_t size = buf.GetCapacity();↩
if (size != 0)↩
memcpy(newDatabase.SecureBuf + pos, buf, size);↩
newDatabase.SecureSizes.Add((UInt32)size);↩
pos += size;↩
}↩
}↩
*/
newDatabase.ReserveDown();↩
if (opCallback)↩
RINOK(opCallback->ReportOperation(NEventIndexType::kNoIndex, (UInt32)(Int32)-1, NUpdateNotifyOp::kHeader));↩
return S_OK;↩
}↩
}}↩