~ubuntu-branches/ubuntu/precise/p7zip/precise-updates

« back to all changes in this revision

Viewing changes to CPP/7zip/Archive/7z/7zUpdate.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Mohammed Adnène Trojette
  • Date: 2009-02-14 20:12:27 UTC
  • mfrom: (1.1.11 upstream) (2.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20090214201227-go63qxm9ozfdma60
Tags: 4.65~dfsg.1-1
* New upstream release.
* Remove wx2.8 Build-Depends added by mistakes (7zG is not yet
  intended to be built).
* Use dh_clean without -k.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// UpdateMain.cpp
 
1
// 7zUpdate.cpp
2
2
 
3
3
#include "StdAfx.h"
4
4
 
5
 
#include "7zUpdate.h"
 
5
#include "../../Common/LimitedStreams.h"
 
6
#include "../../Common/ProgressUtils.h"
 
7
 
 
8
#include "../../Compress/CopyCoder.h"
 
9
 
 
10
#include "../Common/ItemNameUtils.h"
 
11
 
 
12
#include "7zEncode.h"
6
13
#include "7zFolderInStream.h"
7
 
#include "7zEncode.h"
8
14
#include "7zHandler.h"
9
15
#include "7zOut.h"
10
 
 
11
 
#include "../../Compress/Copy/CopyCoder.h"
12
 
#include "../../Common/ProgressUtils.h"
13
 
#include "../../Common/LimitedStreams.h"
14
 
#include "../../Common/LimitedStreams.h"
15
 
#include "../Common/ItemNameUtils.h"
 
16
#include "7zUpdate.h"
16
17
 
17
18
#ifndef WIN32
18
19
#include "Windows/FileIO.h"
26
27
static const UInt32 kAlgorithmForBCJ2_LZMA = 1;
27
28
static const UInt32 kNumFastBytesForBCJ2_LZMA = 64;
28
29
 
29
 
static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream, 
 
30
static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream,
30
31
    UInt64 position, UInt64 size, ICompressProgressInfo *progress)
31
32
{
32
33
  RINOK(inStream->Seek(position, STREAM_SEEK_SET, 0));
82
83
  RINOZ(MyCompare(c1.NumInStreams, c2.NumInStreams));
83
84
  RINOZ(MyCompare(c1.NumOutStreams, c2.NumOutStreams));
84
85
  RINOZ(MyCompare(c1.MethodID, c2.MethodID));
85
 
  return CompareBuffers(c1.Properties, c2.Properties);
 
86
  return CompareBuffers(c1.Props, c2.Props);
86
87
}
87
88
 
88
89
static int CompareBindPairs(const CBindPair &b1, const CBindPair &b2)
121
122
      db.Folders[i1],
122
123
      db.Folders[i2]));
123
124
  RINOZ(MyCompare(
124
 
      db.NumUnPackStreamsVector[i1],
125
 
      db.NumUnPackStreamsVector[i2]));
126
 
  if (db.NumUnPackStreamsVector[i1] == 0)
 
125
      db.NumUnpackStreamsVector[i1],
 
126
      db.NumUnpackStreamsVector[i2]));
 
127
  if (db.NumUnpackStreamsVector[i1] == 0)
127
128
    return 0;
128
129
  return CompareFiles(
129
130
      db.Files[db.FolderStartFileIndex[i1]],
137
138
  const CObjectVector<CUpdateItem> &updateItems = *(const CObjectVector<CUpdateItem> *)param;
138
139
  const CUpdateItem &u1 = updateItems[*p1];
139
140
  const CUpdateItem &u2 = updateItems[*p2];
140
 
  if (u1.IsDirectory != u2.IsDirectory)
141
 
    return (u1.IsDirectory) ? 1 : -1;
142
 
  if (u1.IsDirectory)
 
141
  if (u1.IsDir != u2.IsDir)
 
142
    return (u1.IsDir) ? 1 : -1;
 
143
  if (u1.IsDir)
143
144
  {
144
145
    if (u1.IsAnti != u2.IsAnti)
145
146
      return (u1.IsAnti ? 1 : -1);
151
152
  return MyStringCompareNoCase(u1.Name, u2.Name);
152
153
}
153
154
 
154
 
static const char *g_Exts = 
155
 
  " lzma 7z ace arc arj bz bz2 deb lzo lzx gz pak rpm sit tgz tbz tbz2 tgz cab ha lha lzh rar zoo" 
 
155
static const char *g_Exts =
 
156
  " lzma 7z ace arc arj bz bz2 deb lzo lzx gz pak rpm sit tgz tbz tbz2 tgz cab ha lha lzh rar zoo"
156
157
  " zip jar ear war msi"
157
158
  " 3gp avi mov mpeg mpg mpe wmv"
158
159
  " aac ape fla flac la mp3 m4a mp4 ofr ogg pac ra rm rka shn swa tta wv wma wav"
165
166
  " iso bin nrg mdf img pdi tar cpio xpi"
166
167
  " vfd vhd vud vmc vsv"
167
168
  " vmdk dsk nvram vmem vmsd vmsn vmss vmtm"
168
 
  " inl inc idl acf asa h hpp hxx c cpp cxx rc java cs pas bas vb cls ctl frm dlg def" 
 
169
  " inl inc idl acf asa h hpp hxx c cpp cxx rc java cs pas bas vb cls ctl frm dlg def"
169
170
  " f77 f f90 f95"
170
171
  " asm sql manifest dep "
171
172
  " mak clw csproj vcproj sln dsp dsw "
216
217
 
217
218
struct CRefItem
218
219
{
 
220
  const CUpdateItem *UpdateItem;
219
221
  UInt32 Index;
220
 
  const CUpdateItem *UpdateItem;
221
222
  UInt32 ExtensionPos;
222
223
  UInt32 NamePos;
223
224
  int ExtensionIndex;
224
 
  CRefItem(UInt32 index, const CUpdateItem &updateItem, bool sortByType):
 
225
  CRefItem(UInt32 index, const CUpdateItem &ui, bool sortByType):
 
226
    UpdateItem(&ui),
225
227
    Index(index),
226
 
    UpdateItem(&updateItem),
227
228
    ExtensionPos(0),
228
229
    NamePos(0),
229
230
    ExtensionIndex(0)
230
231
  {
231
232
    if (sortByType)
232
233
    {
233
 
      int slashPos = GetReverseSlashPos(updateItem.Name);
 
234
      int slashPos = GetReverseSlashPos(ui.Name);
234
235
      NamePos = ((slashPos >= 0) ? (slashPos + 1) : 0);
235
 
      int dotPos = updateItem.Name.ReverseFind(L'.');
 
236
      int dotPos = ui.Name.ReverseFind(L'.');
236
237
      if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0))
237
 
        ExtensionPos = updateItem.Name.Length();
238
 
      else 
 
238
        ExtensionPos = ui.Name.Length();
 
239
      else
239
240
      {
240
241
        ExtensionPos = dotPos + 1;
241
 
        UString us = updateItem.Name.Mid(ExtensionPos);
 
242
        UString us = ui.Name.Mid(ExtensionPos);
242
243
        if (!us.IsEmpty())
243
244
        {
244
245
          us.MakeLower();
268
269
  const CUpdateItem &u1 = *a1.UpdateItem;
269
270
  const CUpdateItem &u2 = *a2.UpdateItem;
270
271
  int n;
271
 
  if (u1.IsDirectory != u2.IsDirectory)
272
 
    return (u1.IsDirectory) ? 1 : -1;
273
 
  if (u1.IsDirectory)
 
272
  if (u1.IsDir != u2.IsDir)
 
273
    return (u1.IsDir) ? 1 : -1;
 
274
  if (u1.IsDir)
274
275
  {
275
276
    if (u1.IsAnti != u2.IsAnti)
276
277
      return (u1.IsAnti ? 1 : -1);
283
284
    RINOZ(MyCompare(a1.ExtensionIndex, a2.ExtensionIndex))
284
285
    RINOZ(MyStringCompareNoCase(u1.Name + a1.ExtensionPos, u2.Name + a2.ExtensionPos));
285
286
    RINOZ(MyStringCompareNoCase(u1.Name + a1.NamePos, u2.Name + a2.NamePos));
286
 
    if (u1.IsLastWriteTimeDefined && u2.IsLastWriteTimeDefined)
287
 
      RINOZ(CompareFileTime(&u1.LastWriteTime, &u2.LastWriteTime));
 
287
    if (!u1.MTimeDefined && u2.MTimeDefined) return 1;
 
288
    if (u1.MTimeDefined && !u2.MTimeDefined) return -1;
 
289
    if (u1.MTimeDefined && u2.MTimeDefined) RINOZ(MyCompare(u1.MTime, u2.MTime));
288
290
    RINOZ(MyCompare(u1.Size, u2.Size))
289
291
  }
290
292
  return MyStringCompareNoCase(u1.Name, u2.Name);
314
316
  return false;
315
317
}
316
318
#else
317
 
static bool IsExeFile(const UString &name)
 
319
static bool IsExeFile(const CUpdateItem &ui)
318
320
{
319
 
  NWindows::NFile::NIO::CInFile file;
320
 
 
321
 
  if (file.Open(name))
322
 
  {
323
 
     char buffer[256];
324
 
     UINT32 processedSize;
325
 
     if (file.Read(buffer,sizeof(buffer),processedSize))
326
 
     {
327
 
        for(UInt32 i = 0; i < processedSize ; i++)
 
321
  if (ui.Attrib & FILE_ATTRIBUTE_UNIX_EXTENSION) {
 
322
    unsigned short st_mode =  ui.Attrib >> 16;
 
323
    if ((st_mode & 00111) && (ui.Size >= 2048))
 
324
    {
 
325
      // file has the execution flag and it's big enought
 
326
      // try to find if the file is a script
 
327
      NWindows::NFile::NIO::CInFile file;
 
328
      if (file.Open(ui.Name))
 
329
      {
 
330
        char buffer[512];
 
331
        UINT32 processedSize;
 
332
        if (file.Read(buffer,sizeof(buffer),processedSize))
328
333
        {
329
 
          if (buffer[i] == 0) return true; // this file is not a text (ascii, utf8, ...) !
330
 
        }
 
334
          for(UInt32 i = 0; i < processedSize ; i++)
 
335
          {
 
336
            if (buffer[i] == 0) 
 
337
            {
 
338
              return true; // this file is not a text (ascii, utf8, ...) !
 
339
            }
 
340
          }
 
341
       }
331
342
     }
 
343
   }
332
344
  } 
333
345
  return false;
334
346
}
338
350
static const UInt64 k_BCJ   = 0x03030103;
339
351
static const UInt64 k_BCJ2  = 0x0303011B;
340
352
 
341
 
static bool GetMethodFull(UInt64 methodID, 
 
353
static bool GetMethodFull(UInt64 methodID,
342
354
    UInt32 numInStreams, CMethodFull &methodResult)
343
355
{
344
356
  methodResult.Id = methodID;
347
359
  return true;
348
360
}
349
361
 
350
 
static bool MakeExeMethod(const CCompressionMethodMode &method, 
 
362
static bool MakeExeMethod(const CCompressionMethodMode &method,
351
363
    bool bcj2Filter, CCompressionMethodMode &exeMethod)
352
364
{
353
365
  exeMethod = method;
360
372
    if (!GetMethodFull(k_LZMA, 1, methodFull))
361
373
      return false;
362
374
    {
363
 
      CProp property;
364
 
      property.Id = NCoderPropID::kAlgorithm;
365
 
      property.Value = kAlgorithmForBCJ2_LZMA;
366
 
      methodFull.Properties.Add(property);
367
 
    }
368
 
    {
369
 
      CProp property;
370
 
      property.Id = NCoderPropID::kMatchFinder;
371
 
      property.Value = kMatchFinderForBCJ2_LZMA;
372
 
      methodFull.Properties.Add(property);
373
 
    }
374
 
    {
375
 
      CProp property;
376
 
      property.Id = NCoderPropID::kDictionarySize;
377
 
      property.Value = kDictionaryForBCJ2_LZMA;
378
 
      methodFull.Properties.Add(property);
379
 
    }
380
 
    {
381
 
      CProp property;
382
 
      property.Id = NCoderPropID::kNumFastBytes;
383
 
      property.Value = kNumFastBytesForBCJ2_LZMA;
384
 
      methodFull.Properties.Add(property);
 
375
      CProp prop;
 
376
      prop.Id = NCoderPropID::kAlgorithm;
 
377
      prop.Value = kAlgorithmForBCJ2_LZMA;
 
378
      methodFull.Props.Add(prop);
 
379
    }
 
380
    {
 
381
      CProp prop;
 
382
      prop.Id = NCoderPropID::kMatchFinder;
 
383
      prop.Value = kMatchFinderForBCJ2_LZMA;
 
384
      methodFull.Props.Add(prop);
 
385
    }
 
386
    {
 
387
      CProp prop;
 
388
      prop.Id = NCoderPropID::kDictionarySize;
 
389
      prop.Value = kDictionaryForBCJ2_LZMA;
 
390
      methodFull.Props.Add(prop);
 
391
    }
 
392
    {
 
393
      CProp prop;
 
394
      prop.Id = NCoderPropID::kNumFastBytes;
 
395
      prop.Value = kNumFastBytesForBCJ2_LZMA;
 
396
      methodFull.Props.Add(prop);
385
397
    }
386
398
 
387
399
    exeMethod.Methods.Add(methodFull);
417
429
    exeMethod.Binds.Add(bind);
418
430
  }
419
431
  return true;
420
 
}   
 
432
}
421
433
 
422
434
static void SplitFilesToGroups(
423
 
    const CCompressionMethodMode &method, 
 
435
    const CCompressionMethodMode &method,
424
436
    bool useFilters, bool maxFilter,
425
437
    const CObjectVector<CUpdateItem> &updateItems,
426
438
    CObjectVector<CSolidGroup> &groups)
436
448
  int i;
437
449
  for (i = 0; i < updateItems.Size(); i++)
438
450
  {
439
 
    const CUpdateItem &updateItem = updateItems[i];
440
 
    if (!updateItem.NewData)
 
451
    const CUpdateItem &ui = updateItems[i];
 
452
    if (!ui.NewData)
441
453
      continue;
442
 
    if (!updateItem.HasStream())
 
454
    if (!ui.HasStream())
443
455
      continue;
444
456
    if (useFilters)
445
457
    {
446
 
      const UString name = updateItem.Name;
 
458
#ifdef _WIN32
 
459
      const UString name = ui.Name;
447
460
      int dotPos = name.ReverseFind(L'.');
448
461
      if (dotPos >= 0)
449
462
      {
454
467
          continue;
455
468
        }
456
469
      }
 
470
#else
 
471
      if (IsExeFile(ui))
 
472
      {
 
473
        exeGroup.Indices.Add(i);
 
474
        continue;
 
475
      }
 
476
#endif
457
477
    }
458
478
    generalGroup.Indices.Add(i);
459
479
  }
467
487
      i++;
468
488
}
469
489
 
470
 
static void FromUpdateItemToFileItem(const CUpdateItem &updateItem, 
471
 
    CFileItem &file)
 
490
static void FromUpdateItemToFileItem(const CUpdateItem &ui,
 
491
    CFileItem &file, CFileItem2 &file2)
472
492
{
473
 
  file.Name = NItemName::MakeLegalName(updateItem.Name);
474
 
  if (updateItem.AttributesAreDefined)
475
 
    file.SetAttributes(updateItem.Attributes);
476
 
  
477
 
  if (updateItem.IsCreationTimeDefined)
478
 
    file.SetCreationTime(updateItem.CreationTime);
479
 
  if (updateItem.IsLastWriteTimeDefined)
480
 
    file.SetLastWriteTime(updateItem.LastWriteTime);
481
 
  if (updateItem.IsLastAccessTimeDefined)
482
 
    file.SetLastAccessTime(updateItem.LastAccessTime);
483
 
  
484
 
  file.UnPackSize = updateItem.Size;
485
 
  file.IsDirectory = updateItem.IsDirectory;
486
 
  file.IsAnti = updateItem.IsAnti;
487
 
  file.HasStream = updateItem.HasStream();
 
493
  file.Name = NItemName::MakeLegalName(ui.Name);
 
494
  if (ui.AttribDefined)
 
495
    file.SetAttrib(ui.Attrib);
 
496
  
 
497
  file2.CTime = ui.CTime;  file2.CTimeDefined = ui.CTimeDefined;
 
498
  file2.ATime = ui.ATime;  file2.ATimeDefined = ui.ATimeDefined;
 
499
  file2.MTime = ui.MTime;  file2.MTimeDefined = ui.MTimeDefined;
 
500
  file2.IsAnti = ui.IsAnti;
 
501
  file2.StartPosDefined = false;
 
502
 
 
503
  file.Size = ui.Size;
 
504
  file.IsDir = ui.IsDir;
 
505
  file.HasStream = ui.HasStream();
488
506
}
489
507
 
490
508
static HRESULT Update2(
491
509
    DECL_EXTERNAL_CODECS_LOC_VARS
492
510
    IInStream *inStream,
493
 
    const CArchiveDatabaseEx *database,
 
511
    const CArchiveDatabaseEx *db,
494
512
    const CObjectVector<CUpdateItem> &updateItems,
 
513
    COutArchive &archive,
 
514
    CArchiveDatabase &newDatabase,
495
515
    ISequentialOutStream *seqOutStream,
496
516
    IArchiveUpdateCallback *updateCallback,
497
517
    const CUpdateOptions &options)
506
526
    return E_NOTIMPL;
507
527
  */
508
528
 
509
 
  UInt64 startBlockSize = database != 0 ? database->ArchiveInfo.StartPosition: 0;
 
529
  UInt64 startBlockSize = db != 0 ? db->ArchiveInfo.StartPosition: 0;
510
530
  if (startBlockSize > 0 && !options.RemoveSfxBlock)
511
531
  {
512
532
    RINOK(WriteRange(inStream, seqOutStream, 0, startBlockSize, NULL));
513
533
  }
514
534
 
515
535
  CRecordVector<int> fileIndexToUpdateIndexMap;
516
 
  if (database != 0)
 
536
  if (db != 0)
517
537
  {
518
 
    fileIndexToUpdateIndexMap.Reserve(database->Files.Size());
519
 
    for (int i = 0; i < database->Files.Size(); i++)
 
538
    fileIndexToUpdateIndexMap.Reserve(db->Files.Size());
 
539
    for (int i = 0; i < db->Files.Size(); i++)
520
540
      fileIndexToUpdateIndexMap.Add(-1);
521
541
  }
522
542
  int i;
528
548
  }
529
549
 
530
550
  CRecordVector<int> folderRefs;
531
 
  if (database != 0)
 
551
  if (db != 0)
532
552
  {
533
 
    for(i = 0; i < database->Folders.Size(); i++)
 
553
    for(i = 0; i < db->Folders.Size(); i++)
534
554
    {
535
555
      CNum indexInFolder = 0;
536
556
      CNum numCopyItems = 0;
537
 
      CNum numUnPackStreams = database->NumUnPackStreamsVector[i];
538
 
      for (CNum fileIndex = database->FolderStartFileIndex[i];
539
 
      indexInFolder < numUnPackStreams; fileIndex++)
 
557
      CNum numUnpackStreams = db->NumUnpackStreamsVector[i];
 
558
      for (CNum fileIndex = db->FolderStartFileIndex[i];
 
559
      indexInFolder < numUnpackStreams; fileIndex++)
540
560
      {
541
 
        if (database->Files[fileIndex].HasStream)
 
561
        if (db->Files[fileIndex].HasStream)
542
562
        {
543
563
          indexInFolder++;
544
564
          int updateIndex = fileIndexToUpdateIndexMap[fileIndex];
547
567
              numCopyItems++;
548
568
        }
549
569
      }
550
 
      if (numCopyItems != numUnPackStreams && numCopyItems != 0)
 
570
      if (numCopyItems != numUnpackStreams && numCopyItems != 0)
551
571
        return E_NOTIMPL; // It needs repacking !!!
552
572
      if (numCopyItems > 0)
553
573
        folderRefs.Add(i);
554
574
    }
555
 
    folderRefs.Sort(CompareFolderRefs, (void *)database);
 
575
    folderRefs.Sort(CompareFolderRefs, (void *)db);
556
576
  }
557
577
 
558
 
  CArchiveDatabase newDatabase;
559
 
 
560
578
  ////////////////////////////
561
579
 
562
 
  COutArchive archive;
563
580
  RINOK(archive.Create(seqOutStream, false));
564
581
  RINOK(archive.SkeepPrefixArchiveHeader());
565
582
  UInt64 complexity = 0;
566
583
  for(i = 0; i < folderRefs.Size(); i++)
567
 
    complexity += database->GetFolderFullPackSize(folderRefs[i]);
 
584
    complexity += db->GetFolderFullPackSize(folderRefs[i]);
568
585
  UInt64 inSizeForReduce = 0;
569
586
  for(i = 0; i < updateItems.Size(); i++)
570
587
  {
571
 
    const CUpdateItem &updateItem = updateItems[i];
572
 
    if (updateItem.NewData)
 
588
    const CUpdateItem &ui = updateItems[i];
 
589
    if (ui.NewData)
573
590
    {
574
 
      complexity += updateItem.Size;
 
591
      complexity += ui.Size;
575
592
      if (numSolidFiles == 1)
576
593
      {
577
 
        if (updateItem.Size > inSizeForReduce)
578
 
          inSizeForReduce = updateItem.Size;
 
594
        if (ui.Size > inSizeForReduce)
 
595
          inSizeForReduce = ui.Size;
579
596
      }
580
597
      else
581
 
        inSizeForReduce += updateItem.Size;
 
598
        inSizeForReduce += ui.Size;
582
599
    }
583
600
  }
584
601
  RINOK(updateCallback->SetTotal(complexity));
598
615
    int folderIndex = folderRefs[i];
599
616
    
600
617
    lps->ProgressOffset = complexity;
601
 
    UInt64 packSize = database->GetFolderFullPackSize(folderIndex);
 
618
    UInt64 packSize = db->GetFolderFullPackSize(folderIndex);
602
619
    RINOK(WriteRange(inStream, archive.SeqStream,
603
 
        database->GetFolderStreamPos(folderIndex, 0), packSize, progress));
 
620
        db->GetFolderStreamPos(folderIndex, 0), packSize, progress));
604
621
    complexity += packSize;
605
622
    
606
 
    const CFolder &folder = database->Folders[folderIndex];
607
 
    CNum startIndex = database->FolderStartPackStreamIndex[folderIndex];
 
623
    const CFolder &folder = db->Folders[folderIndex];
 
624
    CNum startIndex = db->FolderStartPackStreamIndex[folderIndex];
608
625
    for (int j = 0; j < folder.PackStreams.Size(); j++)
609
626
    {
610
 
      newDatabase.PackSizes.Add(database->PackSizes[startIndex + j]);
611
 
      // newDatabase.PackCRCsDefined.Add(database.PackCRCsDefined[startIndex + j]);
612
 
      // newDatabase.PackCRCs.Add(database.PackCRCs[startIndex + j]);
 
627
      newDatabase.PackSizes.Add(db->PackSizes[startIndex + j]);
 
628
      // newDatabase.PackCRCsDefined.Add(db.PackCRCsDefined[startIndex + j]);
 
629
      // newDatabase.PackCRCs.Add(db.PackCRCs[startIndex + j]);
613
630
    }
614
631
    newDatabase.Folders.Add(folder);
615
632
 
616
 
    CNum numUnPackStreams = database->NumUnPackStreamsVector[folderIndex];
617
 
    newDatabase.NumUnPackStreamsVector.Add(numUnPackStreams);
 
633
    CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex];
 
634
    newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams);
618
635
 
619
636
    CNum indexInFolder = 0;
620
 
    for (CNum fi = database->FolderStartFileIndex[folderIndex];
621
 
        indexInFolder < numUnPackStreams; fi++)
 
637
    for (CNum fi = db->FolderStartFileIndex[folderIndex];
 
638
        indexInFolder < numUnpackStreams; fi++)
622
639
    {
623
 
      CFileItem file = database->Files[fi];
 
640
      CFileItem file;
 
641
      CFileItem2 file2;
 
642
      db->GetFile(fi, file, file2);
624
643
      if (file.HasStream)
625
644
      {
626
645
        indexInFolder++;
627
646
        int updateIndex = fileIndexToUpdateIndexMap[fi];
628
647
        if (updateIndex >= 0)
629
648
        {
630
 
          const CUpdateItem &updateItem = updateItems[updateIndex];
631
 
          if (updateItem.NewProperties)
 
649
          const CUpdateItem &ui = updateItems[updateIndex];
 
650
          if (ui.NewProperties)
632
651
          {
633
 
            CFileItem file2;
634
 
            FromUpdateItemToFileItem(updateItem, file2);
635
 
            file2.UnPackSize = file.UnPackSize;
636
 
            file2.FileCRC = file.FileCRC;
637
 
            file2.IsFileCRCDefined = file.IsFileCRCDefined;
638
 
            file2.HasStream = file.HasStream;
639
 
            file = file2;
 
652
            CFileItem uf;
 
653
            FromUpdateItemToFileItem(ui, uf, file2);
 
654
            uf.Size = file.Size;
 
655
            uf.Crc = file.Crc;
 
656
            uf.CrcDefined = file.CrcDefined;
 
657
            uf.HasStream = file.HasStream;
 
658
            file = uf;
640
659
          }
641
660
        }
642
 
        newDatabase.Files.Add(file);
 
661
        newDatabase.AddFile(file, file2);
643
662
      }
644
663
    }
645
664
  }
646
665
 
 
666
  folderRefs.ClearAndFree();
 
667
  fileIndexToUpdateIndexMap.ClearAndFree();
 
668
 
647
669
  /////////////////////////////////////////
648
670
  // Compress New Files
649
671
 
650
672
  CObjectVector<CSolidGroup> groups;
651
 
  SplitFilesToGroups(*options.Method, options.UseFilters, options.MaxFilter, 
 
673
  SplitFilesToGroups(*options.Method, options.UseFilters, options.MaxFilter,
652
674
      updateItems, groups);
653
675
 
654
676
  const UInt32 kMinReduceSize = (1 << 16);
676
698
      UInt32 index = refItems[i].Index;
677
699
      indices.Add(index);
678
700
      /*
679
 
      const CUpdateItem &updateItem = updateItems[index];
 
701
      const CUpdateItem &ui = updateItems[index];
680
702
      CFileItem file;
681
 
      if (updateItem.NewProperties)
682
 
        FromUpdateItemToFileItem(updateItem, file);
 
703
      if (ui.NewProperties)
 
704
        FromUpdateItemToFileItem(ui, file);
683
705
      else
684
 
        file = database.Files[updateItem.IndexInArchive];
685
 
      if (file.IsAnti || file.IsDirectory)
 
706
        file = db.Files[ui.IndexInArchive];
 
707
      if (file.IsAnti || file.IsDir)
686
708
        return E_FAIL;
687
709
      newDatabase.Files.Add(file);
688
710
      */
695
717
      UInt64 totalSize = 0;
696
718
      int numSubFiles;
697
719
      UString prevExtension;
698
 
      for (numSubFiles = 0; i + numSubFiles < numFiles && 
 
720
      for (numSubFiles = 0; i + numSubFiles < numFiles &&
699
721
          numSubFiles < numSolidFiles; numSubFiles++)
700
722
      {
701
 
        const CUpdateItem &updateItem = updateItems[indices[i + numSubFiles]];
702
 
        totalSize += updateItem.Size;
 
723
        const CUpdateItem &ui = updateItems[indices[i + numSubFiles]];
 
724
        totalSize += ui.Size;
703
725
        if (totalSize > options.NumSolidBytes)
704
726
          break;
705
727
        if (options.SolidExtension)
706
728
        {
707
 
          UString ext = updateItem.GetExtension();
 
729
          UString ext = ui.GetExtension();
708
730
          if (numSubFiles == 0)
709
731
            prevExtension = ext;
710
732
          else
724
746
      int startPackIndex = newDatabase.PackSizes.Size();
725
747
      RINOK(encoder.Encode(
726
748
          EXTERNAL_CODECS_LOC_VARS
727
 
          solidInStream, NULL, &inSizeForReduce, folderItem, 
 
749
          solidInStream, NULL, &inSizeForReduce, folderItem,
728
750
          archive.SeqStream, newDatabase.PackSizes, progress));
729
751
 
730
752
      for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
731
753
        lps->OutSize += newDatabase.PackSizes[startPackIndex];
732
754
 
733
 
      lps->InSize += folderItem.GetUnPackSize();
 
755
      lps->InSize += folderItem.GetUnpackSize();
734
756
      // for()
735
757
      // newDatabase.PackCRCsDefined.Add(false);
736
758
      // newDatabase.PackCRCs.Add(0);
737
759
      
738
760
      newDatabase.Folders.Add(folderItem);
739
761
      
740
 
      CNum numUnPackStreams = 0;
 
762
      CNum numUnpackStreams = 0;
741
763
      for (int subIndex = 0; subIndex < numSubFiles; subIndex++)
742
764
      {
743
 
        const CUpdateItem &updateItem = updateItems[indices[i + subIndex]];
 
765
        const CUpdateItem &ui = updateItems[indices[i + subIndex]];
744
766
        CFileItem file;
745
 
        if (updateItem.NewProperties)
746
 
          FromUpdateItemToFileItem(updateItem, file);
 
767
        CFileItem2 file2;
 
768
        if (ui.NewProperties)
 
769
          FromUpdateItemToFileItem(ui, file, file2);
747
770
        else
748
 
          file = database->Files[updateItem.IndexInArchive];
749
 
        if (file.IsAnti || file.IsDirectory)
 
771
          db->GetFile(ui.IndexInArchive, file, file2);
 
772
        if (file2.IsAnti || file.IsDir)
750
773
          return E_FAIL;
751
774
        
752
775
        /*
759
782
          // file.Name += L".locked";
760
783
        }
761
784
 
762
 
        file.FileCRC = inStreamSpec->CRCs[subIndex];
763
 
        file.UnPackSize = inStreamSpec->Sizes[subIndex];
764
 
        if (file.UnPackSize != 0)
 
785
        file.Crc = inStreamSpec->CRCs[subIndex];
 
786
        file.Size = inStreamSpec->Sizes[subIndex];
 
787
        if (file.Size != 0)
765
788
        {
766
 
          file.IsFileCRCDefined = true;
 
789
          file.CrcDefined = true;
767
790
          file.HasStream = true;
768
 
          numUnPackStreams++;
 
791
          numUnpackStreams++;
769
792
        }
770
793
        else
771
794
        {
772
 
          file.IsFileCRCDefined = false;
 
795
          file.CrcDefined = false;
773
796
          file.HasStream = false;
774
797
        }
775
 
        newDatabase.Files.Add(file);
 
798
        newDatabase.AddFile(file, file2);
776
799
      }
777
 
      // numUnPackStreams = 0 is very bad case for locked files
 
800
      // numUnpackStreams = 0 is very bad case for locked files
778
801
      // v3.13 doesn't understand it.
779
 
      newDatabase.NumUnPackStreamsVector.Add(numUnPackStreams);
 
802
      newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams);
780
803
      i += numSubFiles;
781
804
    }
782
805
  }
783
806
 
 
807
  groups.ClearAndFree();
 
808
 
784
809
  {
785
810
    /////////////////////////////////////////
786
811
    // Write Empty Files & Folders
788
813
    CRecordVector<int> emptyRefs;
789
814
    for(i = 0; i < updateItems.Size(); i++)
790
815
    {
791
 
      const CUpdateItem &updateItem = updateItems[i];
792
 
      if (updateItem.NewData)
 
816
      const CUpdateItem &ui = updateItems[i];
 
817
      if (ui.NewData)
793
818
      {
794
 
        if (updateItem.HasStream())
 
819
        if (ui.HasStream())
795
820
          continue;
796
821
      }
797
822
      else
798
 
        if (updateItem.IndexInArchive != -1)
799
 
          if (database->Files[updateItem.IndexInArchive].HasStream)
 
823
        if (ui.IndexInArchive != -1)
 
824
          if (db->Files[ui.IndexInArchive].HasStream)
800
825
            continue;
801
826
      emptyRefs.Add(i);
802
827
    }
803
828
    emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems);
804
 
    for(i = 0; i < emptyRefs.Size(); i++)
 
829
    for (i = 0; i < emptyRefs.Size(); i++)
805
830
    {
806
 
      const CUpdateItem &updateItem = updateItems[emptyRefs[i]];
 
831
      const CUpdateItem &ui = updateItems[emptyRefs[i]];
807
832
      CFileItem file;
808
 
      if (updateItem.NewProperties)
809
 
        FromUpdateItemToFileItem(updateItem, file);
 
833
      CFileItem2 file2;
 
834
      if (ui.NewProperties)
 
835
        FromUpdateItemToFileItem(ui, file, file2);
810
836
      else
811
 
        file = database->Files[updateItem.IndexInArchive];
812
 
      newDatabase.Files.Add(file);
813
 
    }
814
 
  }
815
 
    
816
 
  /*
817
 
  if (newDatabase.Files.Size() != updateItems.Size())
818
 
    return E_FAIL;
819
 
  */
820
 
 
821
 
  return archive.WriteDatabase(EXTERNAL_CODECS_LOC_VARS
822
 
      newDatabase, options.HeaderMethod, options.HeaderOptions);
823
 
}
824
 
 
825
 
#ifdef _7Z_VOL
826
 
 
827
 
static const UInt64 k_Copy = 0x0;
828
 
 
829
 
static HRESULT WriteVolumeHeader(COutArchive &archive, CFileItem &file, const CUpdateOptions &options)
830
 
{
831
 
  CCoderInfo coder;
832
 
  coder.NumInStreams = coder.NumOutStreams = 1;
833
 
  coder.MethodID = k_Copy;
834
 
  
835
 
  CFolder folder;
836
 
  folder.Coders.Add(coder);
837
 
  folder.PackStreams.Add(0);
838
 
  
839
 
  CNum numUnPackStreams = 0;
840
 
  if (file.UnPackSize != 0)
841
 
  {
842
 
    file.IsFileCRCDefined = true;
843
 
    file.HasStream = true;
844
 
    numUnPackStreams++;
845
 
  }
846
 
  else
847
 
  {
848
 
    throw 1;
849
 
    file.IsFileCRCDefined = false;
850
 
    file.HasStream = false;
851
 
  }
852
 
  folder.UnPackSizes.Add(file.UnPackSize);
853
 
  
854
 
  CArchiveDatabase newDatabase;
855
 
  newDatabase.Files.Add(file);
856
 
  newDatabase.Folders.Add(folder);
857
 
  newDatabase.NumUnPackStreamsVector.Add(numUnPackStreams);
858
 
  newDatabase.PackSizes.Add(file.UnPackSize);
859
 
  newDatabase.PackCRCsDefined.Add(false);
860
 
  newDatabase.PackCRCs.Add(file.FileCRC);
861
 
  
862
 
  return archive.WriteDatabase(newDatabase, 
863
 
      options.HeaderMethod, 
864
 
      false, 
865
 
      false);
866
 
}
867
 
 
868
 
HRESULT UpdateVolume(
869
 
    IInStream *inStream,
870
 
    const CArchiveDatabaseEx *database,
871
 
    CObjectVector<CUpdateItem> &updateItems,
872
 
    ISequentialOutStream *seqOutStream,
873
 
    IArchiveUpdateCallback *updateCallback,
874
 
    const CUpdateOptions &options)
875
 
{
876
 
  if (updateItems.Size() != 1)
877
 
    return E_NOTIMPL;
878
 
 
879
 
  CMyComPtr<IArchiveUpdateCallback2> volumeCallback;
880
 
  RINOK(updateCallback->QueryInterface(IID_IArchiveUpdateCallback2, (void **)&volumeCallback));
881
 
  if (!volumeCallback)
882
 
    return E_NOTIMPL;
883
 
 
884
 
  CMyComPtr<ISequentialInStream> fileStream;
885
 
  HRESULT result = updateCallback->GetStream(0, &fileStream);
886
 
  if (result != S_OK && result != S_FALSE)
887
 
    return result;
888
 
  if (result == S_FALSE)
889
 
    return E_FAIL;
890
 
  
891
 
  CFileItem file;
892
 
  
893
 
  const CUpdateItem &updateItem = updateItems[0];
894
 
  if (updateItem.NewProperties)
895
 
    FromUpdateItemToFileItem(updateItem, file);
896
 
  else
897
 
    file = database->Files[updateItem.IndexInArchive];
898
 
  if (file.IsAnti || file.IsDirectory)
899
 
    return E_FAIL;
900
 
 
901
 
  UInt64 complexity = 0;
902
 
  file.IsStartPosDefined = true;
903
 
  file.StartPos = 0;
904
 
  for (UInt64 volumeIndex = 0; true; volumeIndex++)
905
 
  { 
906
 
    UInt64 volSize;
907
 
    RINOK(volumeCallback->GetVolumeSize(volumeIndex, &volSize));
908
 
    UInt64 pureSize = COutArchive::GetVolPureSize(volSize, file.Name.Length(), true);
909
 
    CMyComPtr<ISequentialOutStream> volumeStream;
910
 
    RINOK(volumeCallback->GetVolumeStream(volumeIndex, &volumeStream));
911
 
   
912
 
    COutArchive archive;
913
 
    RINOK(archive.Create(volumeStream, true));
914
 
    RINOK(archive.SkeepPrefixArchiveHeader());
915
 
        
916
 
    CSequentialInStreamWithCRC *inCrcStreamSpec = new CSequentialInStreamWithCRC;
917
 
    CMyComPtr<ISequentialInStream> inCrcStream = inCrcStreamSpec;
918
 
    inCrcStreamSpec->Init(fileStream);
919
 
 
920
 
    RINOK(WriteRange(inCrcStream, volumeStream, pureSize, updateCallback, complexity));
921
 
    file.UnPackSize = inCrcStreamSpec->GetSize();
922
 
    if (file.UnPackSize == 0)
923
 
      break;
924
 
    file.FileCRC = inCrcStreamSpec->GetCRC();
925
 
    RINOK(WriteVolumeHeader(archive, file, options));
926
 
    file.StartPos += file.UnPackSize;
927
 
    if (file.UnPackSize < pureSize)
928
 
      break;
929
 
  }
930
 
  return S_OK;
931
 
}
932
 
 
933
 
class COutVolumeStream: 
934
 
  public ISequentialOutStream,
935
 
  public CMyUnknownImp
936
 
{
937
 
  int _volIndex;
938
 
  UInt64 _volSize;
939
 
  UInt64 _curPos;
940
 
  CMyComPtr<ISequentialOutStream> _volumeStream;
941
 
  COutArchive _archive;
942
 
  CCRC _crc;
943
 
 
944
 
public:
945
 
  MY_UNKNOWN_IMP
946
 
 
947
 
  CFileItem _file;
948
 
  CUpdateOptions _options;
949
 
  CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
950
 
  void Init(IArchiveUpdateCallback2 *volumeCallback, 
951
 
      const UString &name)  
952
 
  { 
953
 
    _file.Name = name;
954
 
    _file.IsStartPosDefined = true;
955
 
    _file.StartPos = 0;
956
 
    
957
 
    VolumeCallback = volumeCallback;
958
 
    _volIndex = 0;
959
 
    _volSize = 0;
960
 
  }
961
 
  
962
 
  HRESULT Flush();
963
 
  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
964
 
};
965
 
 
966
 
HRESULT COutVolumeStream::Flush()
967
 
{
968
 
  if (_volumeStream)
969
 
  {
970
 
    _file.UnPackSize = _curPos;
971
 
    _file.FileCRC = _crc.GetDigest();
972
 
    RINOK(WriteVolumeHeader(_archive, _file, _options));
973
 
    _archive.Close();
974
 
    _volumeStream.Release();
975
 
    _file.StartPos += _file.UnPackSize;
976
 
  }
977
 
  return S_OK;
978
 
}
979
 
 
980
 
STDMETHODIMP COutVolumeStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
981
 
{
982
 
  if(processedSize != NULL)
983
 
    *processedSize = 0;
984
 
  while(size > 0)
985
 
  {
986
 
    if (!_volumeStream)
987
 
    {
988
 
      RINOK(VolumeCallback->GetVolumeSize(_volIndex, &_volSize));
989
 
      RINOK(VolumeCallback->GetVolumeStream(_volIndex, &_volumeStream));
990
 
      _volIndex++;
991
 
      _curPos = 0;
992
 
      RINOK(_archive.Create(_volumeStream, true));
993
 
      RINOK(_archive.SkeepPrefixArchiveHeader());
994
 
      _crc.Init();
995
 
      continue;
996
 
    }
997
 
    UInt64 pureSize = COutArchive::GetVolPureSize(_volSize, _file.Name.Length());
998
 
    UInt32 curSize = (UInt32)MyMin(UInt64(size), pureSize - _curPos);
999
 
 
1000
 
    _crc.Update(data, curSize);
1001
 
    UInt32 realProcessed;
1002
 
    RINOK(_volumeStream->Write(data, curSize, &realProcessed))
1003
 
    data = (void *)((Byte *)data + realProcessed);
1004
 
    size -= realProcessed;
1005
 
    if(processedSize != NULL)
1006
 
      *processedSize += realProcessed;
1007
 
    _curPos += realProcessed;
1008
 
    if (realProcessed != curSize && realProcessed == 0)
1009
 
      return E_FAIL;
1010
 
    if (_curPos == pureSize)
1011
 
    {
1012
 
      RINOK(Flush());
1013
 
    }
1014
 
  }
1015
 
  return S_OK;
1016
 
}
1017
 
 
1018
 
#endif
 
837
        db->GetFile(ui.IndexInArchive, file, file2);
 
838
      newDatabase.AddFile(file, file2);
 
839
    }
 
840
  }
 
841
    
 
842
  newDatabase.ReserveDown();
 
843
  return S_OK;
 
844
}
1019
845
 
1020
846
HRESULT Update(
1021
847
    DECL_EXTERNAL_CODECS_LOC_VARS
1022
848
    IInStream *inStream,
1023
 
    const CArchiveDatabaseEx *database,
 
849
    const CArchiveDatabaseEx *db,
1024
850
    const CObjectVector<CUpdateItem> &updateItems,
 
851
    COutArchive &archive,
 
852
    CArchiveDatabase &newDatabase,
1025
853
    ISequentialOutStream *seqOutStream,
1026
854
    IArchiveUpdateCallback *updateCallback,
1027
855
    const CUpdateOptions &options)
1028
856
{
1029
 
  #ifdef _7Z_VOL
1030
 
  if (seqOutStream)
1031
 
  #endif
1032
 
    return Update2(
 
857
  return Update2(
1033
858
        EXTERNAL_CODECS_LOC_VARS
1034
 
        inStream, database, updateItems,
1035
 
        seqOutStream, updateCallback, options);
1036
 
  #ifdef _7Z_VOL
1037
 
  if (options.VolumeMode)
1038
 
    return UpdateVolume(inStream, database, updateItems,
1039
 
      seqOutStream, updateCallback, options);
1040
 
  COutVolumeStream *volStreamSpec = new COutVolumeStream;
1041
 
  CMyComPtr<ISequentialOutStream> volStream = volStreamSpec;
1042
 
  CMyComPtr<IArchiveUpdateCallback2> volumeCallback;
1043
 
  RINOK(updateCallback->QueryInterface(IID_IArchiveUpdateCallback2, (void **)&volumeCallback));
1044
 
  if (!volumeCallback)
1045
 
    return E_NOTIMPL;
1046
 
  volStreamSpec->Init(volumeCallback, L"a.7z");
1047
 
  volStreamSpec->_options = options;
1048
 
  RINOK(Update2(inStream, database, updateItems,
1049
 
    volStream, updateCallback, options));
1050
 
  return volStreamSpec->Flush();
1051
 
  #endif
 
859
        inStream, db, updateItems,
 
860
        archive, newDatabase, seqOutStream, updateCallback, options);
1052
861
}
1053
862
 
1054
863
}}