Răsfoiți Sursa

Upgraded lzma sdk to 4.57.

Ryan C. Gordon 18 ani în urmă
părinte
comite
4e457760a2
100 a modificat fișierele cu 17297 adăugiri și 0 ștergeri
  1. 237 0
      lzma/7zC.txt
  2. 471 0
      lzma/7zFormat.txt
  3. 32 0
      lzma/C/7zCrc.c
  4. 21 0
      lzma/C/7zCrc.h
  5. 40 0
      lzma/C/7zCrcT8.c
  6. 119 0
      lzma/C/Alloc.c
  7. 29 0
      lzma/C/Alloc.h
  8. 70 0
      lzma/C/Archive/7z/7zAlloc.c
  9. 20 0
      lzma/C/Archive/7z/7zAlloc.h
  10. 29 0
      lzma/C/Archive/7z/7zBuffer.c
  11. 19 0
      lzma/C/Archive/7z/7zBuffer.h
  12. 341 0
      lzma/C/Archive/7z/7zDecode.c
  13. 20 0
      lzma/C/Archive/7z/7zDecode.h
  14. 119 0
      lzma/C/Archive/7z/7zExtract.c
  15. 40 0
      lzma/C/Archive/7z/7zExtract.h
  16. 5 0
      lzma/C/Archive/7z/7zHeader.c
  17. 55 0
      lzma/C/Archive/7z/7zHeader.h
  18. 1314 0
      lzma/C/Archive/7z/7zIn.c
  19. 55 0
      lzma/C/Archive/7z/7zIn.h
  20. 134 0
      lzma/C/Archive/7z/7zItem.c
  21. 95 0
      lzma/C/Archive/7z/7zItem.h
  22. 428 0
      lzma/C/Archive/7z/7zMain.c
  23. 10 0
      lzma/C/Archive/7z/7zMethodID.c
  24. 10 0
      lzma/C/Archive/7z/7zMethodID.h
  25. 211 0
      lzma/C/Archive/7z/7z_C.dsp
  26. 29 0
      lzma/C/Archive/7z/7z_C.dsw
  27. 74 0
      lzma/C/Archive/7z/makefile
  28. 55 0
      lzma/C/Archive/7z/makefile.gcc
  29. 26 0
      lzma/C/Compress/Branch/BranchARM.c
  30. 10 0
      lzma/C/Compress/Branch/BranchARM.h
  31. 35 0
      lzma/C/Compress/Branch/BranchARMThumb.c
  32. 10 0
      lzma/C/Compress/Branch/BranchARMThumb.h
  33. 66 0
      lzma/C/Compress/Branch/BranchIA64.c
  34. 10 0
      lzma/C/Compress/Branch/BranchIA64.h
  35. 36 0
      lzma/C/Compress/Branch/BranchPPC.c
  36. 10 0
      lzma/C/Compress/Branch/BranchPPC.h
  37. 36 0
      lzma/C/Compress/Branch/BranchSPARC.c
  38. 10 0
      lzma/C/Compress/Branch/BranchSPARC.h
  39. 51 0
      lzma/C/Compress/Branch/BranchTypes.h
  40. 84 0
      lzma/C/Compress/Branch/BranchX86.c
  41. 12 0
      lzma/C/Compress/Branch/BranchX86.h
  42. 135 0
      lzma/C/Compress/Branch/BranchX86_2.c
  43. 28 0
      lzma/C/Compress/Branch/BranchX86_2.h
  44. 146 0
      lzma/C/Compress/Huffman/HuffmanEncode.c
  45. 18 0
      lzma/C/Compress/Huffman/HuffmanEncode.h
  46. 53 0
      lzma/C/Compress/Lz/LzHash.h
  47. 742 0
      lzma/C/Compress/Lz/MatchFinder.c
  48. 106 0
      lzma/C/Compress/Lz/MatchFinder.h
  49. 806 0
      lzma/C/Compress/Lz/MatchFinderMt.c
  50. 95 0
      lzma/C/Compress/Lz/MatchFinderMt.h
  51. 584 0
      lzma/C/Compress/Lzma/LzmaDecode.c
  52. 113 0
      lzma/C/Compress/Lzma/LzmaDecode.h
  53. 712 0
      lzma/C/Compress/Lzma/LzmaDecodeSize.c
  54. 521 0
      lzma/C/Compress/Lzma/LzmaStateDecode.c
  55. 96 0
      lzma/C/Compress/Lzma/LzmaStateDecode.h
  56. 195 0
      lzma/C/Compress/Lzma/LzmaStateTest.c
  57. 342 0
      lzma/C/Compress/Lzma/LzmaTest.c
  58. 45 0
      lzma/C/Compress/Lzma/LzmaTypes.h
  59. 18 0
      lzma/C/CpuArch.h
  60. 19 0
      lzma/C/IStream.h
  61. 92 0
      lzma/C/Sort.c
  62. 11 0
      lzma/C/Sort.h
  63. 106 0
      lzma/C/Threads.c
  64. 69 0
      lzma/C/Threads.h
  65. 100 0
      lzma/C/Types.h
  66. BIN
      lzma/CPP/7zip/Archive/7z/7z.ico
  67. 3 0
      lzma/CPP/7zip/Archive/7z/7zCompressionMode.cpp
  68. 50 0
      lzma/CPP/7zip/Archive/7z/7zCompressionMode.h
  69. 330 0
      lzma/CPP/7zip/Archive/7z/7zDecode.cpp
  70. 68 0
      lzma/CPP/7zip/Archive/7z/7zDecode.h
  71. 453 0
      lzma/CPP/7zip/Archive/7z/7zEncode.cpp
  72. 55 0
      lzma/CPP/7zip/Archive/7z/7zEncode.h
  73. 269 0
      lzma/CPP/7zip/Archive/7z/7zExtract.cpp
  74. 130 0
      lzma/CPP/7zip/Archive/7z/7zFolderInStream.cpp
  75. 66 0
      lzma/CPP/7zip/Archive/7z/7zFolderInStream.h
  76. 165 0
      lzma/CPP/7zip/Archive/7z/7zFolderOutStream.cpp
  77. 60 0
      lzma/CPP/7zip/Archive/7z/7zFolderOutStream.h
  78. 793 0
      lzma/CPP/7zip/Archive/7z/7zHandler.cpp
  79. 146 0
      lzma/CPP/7zip/Archive/7z/7zHandler.h
  80. 464 0
      lzma/CPP/7zip/Archive/7z/7zHandlerOut.cpp
  81. 27 0
      lzma/CPP/7zip/Archive/7z/7zHeader.cpp
  82. 96 0
      lzma/CPP/7zip/Archive/7z/7zHeader.h
  83. 1206 0
      lzma/CPP/7zip/Archive/7z/7zIn.cpp
  84. 235 0
      lzma/CPP/7zip/Archive/7z/7zIn.h
  85. 184 0
      lzma/CPP/7zip/Archive/7z/7zItem.h
  86. 1026 0
      lzma/CPP/7zip/Archive/7z/7zOut.cpp
  87. 193 0
      lzma/CPP/7zip/Archive/7z/7zOut.h
  88. 162 0
      lzma/CPP/7zip/Archive/7z/7zProperties.cpp
  89. 22 0
      lzma/CPP/7zip/Archive/7z/7zProperties.h
  90. 18 0
      lzma/CPP/7zip/Archive/7z/7zRegister.cpp
  91. 24 0
      lzma/CPP/7zip/Archive/7z/7zSpecStream.cpp
  92. 35 0
      lzma/CPP/7zip/Archive/7z/7zSpecStream.h
  93. 1029 0
      lzma/CPP/7zip/Archive/7z/7zUpdate.cpp
  94. 80 0
      lzma/CPP/7zip/Archive/7z/7zUpdate.h
  95. 3 0
      lzma/CPP/7zip/Archive/7z/StdAfx.cpp
  96. 9 0
      lzma/CPP/7zip/Archive/7z/StdAfx.h
  97. 6 0
      lzma/CPP/7zip/Archive/Archive.def
  98. 9 0
      lzma/CPP/7zip/Archive/Archive2.def
  99. 130 0
      lzma/CPP/7zip/Archive/ArchiveExports.cpp
  100. 121 0
      lzma/CPP/7zip/Archive/Common/CoderMixer2.cpp

+ 237 - 0
lzma/7zC.txt

@@ -0,0 +1,237 @@
+7z ANSI-C Decoder 4.48
+----------------------
+
+7z ANSI-C Decoder 4.48 Copyright (C) 1999-2006 Igor Pavlov
+
+7z ANSI-C provides 7z/LZMA decoding.
+7z ANSI-C version is simplified version ported from C++ code.
+
+LZMA is default and general compression method of 7z format
+in 7-Zip compression program (www.7-zip.org). LZMA provides high 
+compression ratio and very fast decompression.
+
+
+LICENSE
+-------
+
+Read lzma.txt for information about license.
+
+
+Files
+---------------------
+
+7zAlloc.*    - Allocate and Free
+7zBuffer.*   - Buffer structure
+7zCrc.*      - CRC32 code
+7zDecode.*   - Low level memory->memory decoding
+7zExtract.*  - High level stream->memory decoding
+7zHeader.*   - .7z format constants
+7zIn.*       - .7z archive opening
+7zItem.*     - .7z structures
+7zMain.c     - Test application
+7zMethodID.* - MethodID structure
+7zTypes.h    - Base types and constants
+
+
+How To Use
+----------
+
+You must download 7-Zip program from www.7-zip.org.
+
+You can create .7z archive with 7z.exe or 7za.exe:
+
+  7za.exe a archive.7z *.htm -r -mx -m0fb=255
+
+If you have big number of files in archive, and you need fast extracting, 
+you can use partly-solid archives:
+  
+  7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K
+
+In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only 
+512KB for extracting one file from such archive.
+
+
+Limitations of current version of 7z ANSI-C Decoder
+---------------------------------------------------
+
+ - It reads only "FileName", "Size", "LastWriteTime" and "CRC" information for each file in archive.
+ - It supports only LZMA and Copy (no compression) methods with BCJ or BCJ2 filters.
+ - It converts original UTF-16 Unicode file names to UTF-8 Unicode file names.
+ 
+These limitations will be fixed in future versions.
+
+
+Using 7z ANSI-C Decoder Test application:
+-----------------------------------------
+
+Usage: 7zDec <command> <archive_name>
+
+<Command>:
+  e: Extract files from archive
+  l: List contents of archive
+  t: Test integrity of archive
+
+Example: 
+
+  7zDec l archive.7z
+
+lists contents of archive.7z
+
+  7zDec e archive.7z
+
+extracts files from archive.7z to current folder.
+
+
+How to use .7z Decoder
+----------------------
+
+.7z Decoder can be compiled in one of two modes:
+
+1) Default mode. In that mode 7z Decoder will read full compressed 
+   block to RAM before decompressing.
+  
+2) Mode with defined _LZMA_IN_CB. In that mode 7z Decoder can read
+   compressed block by parts. And you can specify desired buffer size. 
+   So memory requirements can be reduced. But decompressing speed will 
+   be 5-10% lower and code size is slightly larger.
+
+   
+Memory allocation
+~~~~~~~~~~~~~~~~~
+
+7z Decoder uses two memory pools:
+1) Temporary pool
+2) Main pool
+Such scheme can allow you to avoid fragmentation of allocated blocks.
+
+Steps for using 7z decoder
+--------------------------
+
+Use code at 7zMain.c as example.
+
+1) Declare variables:
+  inStream                     /* implements ISzInStream interface */
+  CArchiveDatabaseEx db;       /* 7z archive database structure */
+  ISzAlloc allocImp;           /* memory functions for main pool */
+  ISzAlloc allocTempImp;       /* memory functions for temporary pool */
+
+2) call InitCrcTable(); function to initialize CRC structures.
+
+3) call SzArDbExInit(&db); function to initialize db structures.
+
+4) call SzArchiveOpen(inStream, &db, &allocMain, &allocTemp) to open archive
+
+This function opens archive "inStream" and reads headers to "db".
+All items in "db" will be allocated with "allocMain" functions.
+SzArchiveOpen function allocates and frees temporary structures by "allocTemp" functions.
+
+5) List items or Extract items
+
+  Listing code:
+  ~~~~~~~~~~~~~
+    {
+      UInt32 i;
+      for (i = 0; i < db.Database.NumFiles; i++)
+      {
+        CFileItem *f = db.Database.Files + i;
+        printf("%10d  %s\n", (int)f->Size, f->Name);
+      }
+    }
+
+  Extracting code:
+  ~~~~~~~~~~~~~~~~
+
+  SZ_RESULT SzExtract(
+    ISzInStream *inStream, 
+    CArchiveDatabaseEx *db,
+    UInt32 fileIndex,         /* index of file */
+    UInt32 *blockIndex,       /* index of solid block */
+    Byte **outBuffer,         /* pointer to pointer to output buffer (allocated with allocMain) */
+    size_t *outBufferSize,    /* buffer size for output buffer */
+    size_t *offset,           /* offset of stream for required file in *outBuffer */
+    size_t *outSizeProcessed, /* size of file in *outBuffer */
+    ISzAlloc *allocMain,
+    ISzAlloc *allocTemp);
+
+  If you need to decompress more than one file, you can send these values from previous call:
+    blockIndex, 
+    outBuffer, 
+    outBufferSize,
+  You can consider "outBuffer" as cache of solid block. If your archive is solid, 
+  it will increase decompression speed.
+
+  After decompressing you must free "outBuffer":
+  allocImp.Free(outBuffer);
+
+6) call SzArDbExFree(&db, allocImp.Free) to free allocated items in "db".
+
+
+
+
+Memory requirements for .7z decoding 
+------------------------------------
+
+Memory usage for Archive opening:
+  - Temporary pool:
+     - Memory for compressed .7z headers (if _LZMA_IN_CB is not defined)
+     - Memory for uncompressed .7z headers
+     - some other temporary blocks
+  - Main pool:
+     - Memory for database: 
+       Estimated size of one file structures in solid archive:
+         - Size (4 or 8 Bytes)
+         - CRC32 (4 bytes)
+         - LastWriteTime (8 bytes)
+         - Some file information (4 bytes)
+         - File Name (variable length) + pointer + allocation structures
+
+Memory usage for archive Decompressing:
+  - Temporary pool:
+     - Memory for compressed solid block (if _LZMA_IN_CB is not defined)
+     - Memory for LZMA decompressing structures
+  - Main pool:
+     - Memory for decompressed solid block
+     - Memory for temprorary buffers, if BCJ2 fileter is used. Usually these 
+       temprorary buffers can be about 15% of solid block size. 
+  
+
+If _LZMA_IN_CB is defined, 7z Decoder will not allocate memory for 
+compressed blocks. Instead of this, you must allocate buffer with desired 
+size before calling 7z Decoder. Use 7zMain.c as example.
+
+
+
+EXIT codes
+-----------
+
+7z Decoder functions can return one of the following codes:
+
+#define SZ_OK (0)
+#define SZE_DATA_ERROR (1)
+#define SZE_OUTOFMEMORY (2)
+#define SZE_CRC_ERROR (3)
+
+#define SZE_NOTIMPL (4)
+#define SZE_FAIL (5)
+
+#define SZE_ARCHIVE_ERROR (6)
+
+
+
+LZMA Defines
+------------
+
+_LZMA_IN_CB       - Use special callback mode for input stream to reduce memory requirements
+
+_SZ_FILE_SIZE_32  - define it if you need only support for files smaller than 4 GB
+_SZ_NO_INT_64     - define it if your compiler doesn't support long long int or __int64.
+
+_LZMA_PROB32      - it can increase LZMA decompressing speed on some 32-bit CPUs.
+
+_SZ_ALLOC_DEBUG   - define it if you want to debug alloc/free operations to stderr.
+
+
+---
+
+http://www.7-zip.org
+http://www.7-zip.org/support.html

+ 471 - 0
lzma/7zFormat.txt

@@ -0,0 +1,471 @@
+7z Format description (2.30 Beta 25)
+-----------------------------------
+
+This file contains description of 7z archive format. 
+7z archive can contain files compressed with any method.
+See "Methods.txt" for description for defined compressing methods.
+
+
+Format structure Overview
+-------------------------
+
+Some fields can be optional.
+
+Archive structure
+~~~~~~~~~~~~~~~~~  
+SignatureHeader
+[PackedStreams]
+[PackedStreamsForHeaders]
+[
+  Header 
+  or 
+  {
+    Packed Header
+    HeaderInfo
+  }
+]
+
+
+
+Header structure
+~~~~~~~~~~~~~~~~  
+{
+  ArchiveProperties
+  AdditionalStreams
+  {
+    PackInfo
+    {
+      PackPos
+      NumPackStreams
+      Sizes[NumPackStreams]
+      CRCs[NumPackStreams]
+    }
+    CodersInfo
+    {
+      NumFolders
+      Folders[NumFolders]
+      {
+        NumCoders
+        CodersInfo[NumCoders]
+        {
+          ID
+          NumInStreams;
+          NumOutStreams;
+          PropertiesSize
+          Properties[PropertiesSize]
+        }
+        NumBindPairs
+        BindPairsInfo[NumBindPairs]
+        {
+          InIndex;
+          OutIndex;
+        }
+        PackedIndices
+      }
+      UnPackSize[Folders][Folders.NumOutstreams]
+      CRCs[NumFolders]
+    }
+    SubStreamsInfo
+    {
+      NumUnPackStreamsInFolders[NumFolders];
+      UnPackSizes[]
+      CRCs[]
+    }
+  }
+  MainStreamsInfo
+  {
+    (Same as in AdditionalStreams)
+  }
+  FilesInfo
+  {
+    NumFiles
+    Properties[]
+    {
+      ID
+      Size
+      Data
+    }
+  }
+}
+
+HeaderInfo structure
+~~~~~~~~~~~~~~~~~~~~
+{
+  (Same as in AdditionalStreams)
+}
+
+
+
+Notes about Notation and encoding
+---------------------------------
+
+7z uses little endian encoding.
+
+7z archive format has optional headers that are marked as
+[]
+Header
+[]
+
+REAL_UINT64 means real UINT64.
+
+UINT64 means real UINT64 encoded with the following scheme:
+
+  Size of encoding sequence depends from first byte:
+  First_Byte  Extra_Bytes        Value
+  (binary)   
+  0xxxxxxx               : ( xxxxxxx           )
+  10xxxxxx    BYTE y[1]  : (  xxxxxx << (8 * 1)) + y
+  110xxxxx    BYTE y[2]  : (   xxxxx << (8 * 2)) + y
+  ...
+  1111110x    BYTE y[6]  : (       x << (8 * 6)) + y
+  11111110    BYTE y[7]  :                         y
+  11111111    BYTE y[8]  :                         y
+
+
+
+Property IDs
+------------
+
+0x00 = kEnd,
+
+0x01 = kHeader,
+
+0x02 = kArchiveProperties,
+    
+0x03 = kAdditionalStreamsInfo,
+0x04 = kMainStreamsInfo,
+0x05 = kFilesInfo,
+    
+0x06 = kPackInfo,
+0x07 = kUnPackInfo,
+0x08 = kSubStreamsInfo,
+
+0x09 = kSize,
+0x0A = kCRC,
+
+0x0B = kFolder,
+
+0x0C = kCodersUnPackSize,
+0x0D = kNumUnPackStream,
+
+0x0E = kEmptyStream,
+0x0F = kEmptyFile,
+0x10 = kAnti,
+
+0x11 = kName,
+0x12 = kCreationTime,
+0x13 = kLastAccessTime,
+0x14 = kLastWriteTime,
+0x15 = kWinAttributes,
+0x16 = kComment,
+
+0x17 = kEncodedHeader,
+
+
+7z format headers
+-----------------
+
+SignatureHeader
+~~~~~~~~~~~~~~~
+  BYTE kSignature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
+
+  ArchiveVersion
+  {
+    BYTE Major;   // now = 0
+    BYTE Minor;   // now = 2
+  };
+
+  UINT32 StartHeaderCRC;
+
+  StartHeader
+  {
+    REAL_UINT64 NextHeaderOffset
+    REAL_UINT64 NextHeaderSize
+    UINT32 NextHeaderCRC
+  }
+
+
+...........................
+
+
+ArchiveProperties
+~~~~~~~~~~~~~~~~~
+BYTE NID::kArchiveProperties (0x02)
+for (;;)
+{
+  BYTE PropertyType;
+  if (aType == 0)
+    break;
+  UINT64 PropertySize;
+  BYTE PropertyData[PropertySize];
+}
+
+
+Digests (NumStreams)
+~~~~~~~~~~~~~~~~~~~~~
+  BYTE AllAreDefined
+  if (AllAreDefined == 0)
+  {
+    for(NumStreams)
+      BIT Defined
+  }
+  UINT32 CRCs[NumDefined]
+
+
+PackInfo
+~~~~~~~~~~~~
+  BYTE NID::kPackInfo  (0x06)
+  UINT64 PackPos
+  UINT64 NumPackStreams
+
+  []
+  BYTE NID::kSize    (0x09)
+  UINT64 PackSizes[NumPackStreams]
+  []
+
+  []
+  BYTE NID::kCRC      (0x0A)
+  PackStreamDigests[NumPackStreams]
+  []
+
+  BYTE NID::kEnd
+
+
+Folder
+~~~~~~
+  UINT64 NumCoders;
+  for (NumCoders)
+  {
+    BYTE 
+    {
+      0:3 DecompressionMethod.IDSize
+      4:
+        0 - IsSimple
+        1 - Is not simple
+      5:
+        0 - No Attributes
+        1 - There Are Attributes
+      7:
+        0 - Last Method in Alternative_Method_List
+        1 - There are more alternative methods
+    } 
+    BYTE DecompressionMethod.ID[DecompressionMethod.IDSize]
+    if (!IsSimple)
+    {
+      UINT64 NumInStreams;
+      UINT64 NumOutStreams;
+    }
+    if (DecompressionMethod[0] != 0)
+    {
+      UINT64 PropertiesSize
+      BYTE Properties[PropertiesSize]
+    }
+  }
+    
+  NumBindPairs = NumOutStreamsTotal - 1;
+
+  for (NumBindPairs)
+  {
+    UINT64 InIndex;
+    UINT64 OutIndex;
+  }
+
+  NumPackedStreams = NumInStreamsTotal - NumBindPairs;
+  if (NumPackedStreams > 1)
+    for(NumPackedStreams)
+    {
+      UINT64 Index;
+    };
+
+
+
+
+Coders Info
+~~~~~~~~~~~
+
+  BYTE NID::kUnPackInfo  (0x07)
+
+
+  BYTE NID::kFolder  (0x0B)
+  UINT64 NumFolders
+  BYTE External
+  switch(External)
+  {
+    case 0:
+      Folders[NumFolders]
+    case 1:
+      UINT64 DataStreamIndex
+  }
+
+
+  BYTE ID::kCodersUnPackSize  (0x0C)
+  for(Folders)
+    for(Folder.NumOutStreams)
+     UINT64 UnPackSize;
+
+
+  []
+  BYTE NID::kCRC   (0x0A)
+  UnPackDigests[NumFolders]
+  []
+
+  
+
+  BYTE NID::kEnd
+
+
+
+SubStreams Info
+~~~~~~~~~~~~~~
+  BYTE NID::kSubStreamsInfo; (0x08)
+
+  []
+  BYTE NID::kNumUnPackStream; (0x0D)
+  UINT64 NumUnPackStreamsInFolders[NumFolders];
+  []
+
+
+  []
+  BYTE NID::kSize  (0x09)
+  UINT64 UnPackSizes[]
+  []
+
+
+  []
+  BYTE NID::kCRC  (0x0A)
+  Digests[Number of streams with unknown CRC]
+  []
+
+  
+  BYTE NID::kEnd
+
+
+Streams Info
+~~~~~~~~~~~~
+
+  []
+  PackInfo
+  []
+
+
+  []
+  CodersInfo
+  []
+
+
+  []
+  SubStreamsInfo
+  []
+
+  BYTE NID::kEnd
+
+
+FilesInfo
+~~~~~~~~~
+  BYTE NID::kFilesInfo;  (0x05)
+  UINT64 NumFiles
+
+  for (;;)
+  {
+    BYTE PropertyType;
+    if (aType == 0)
+      break;
+
+    UINT64 Size;
+
+    switch(PropertyType)
+    {
+      kEmptyStream:   (0x0E)
+        for(NumFiles)
+          BIT IsEmptyStream
+
+      kEmptyFile:     (0x0F)
+        for(EmptyStreams)
+          BIT IsEmptyFile
+
+      kAnti:          (0x10)
+        for(EmptyStreams)
+          BIT IsAntiFile
+      
+      case kCreationTime:   (0x12)
+      case kLastAccessTime: (0x13)
+      case kLastWriteTime:  (0x14)
+        BYTE AllAreDefined
+        if (AllAreDefined == 0)
+        {
+          for(NumFiles)
+            BIT TimeDefined
+        }
+        BYTE External;
+        if(External != 0)
+          UINT64 DataIndex
+        []
+        for(Definded Items)
+          UINT32 Time
+        []
+      
+      kNames:     (0x11)
+        BYTE External;
+        if(External != 0)
+          UINT64 DataIndex
+        []
+        for(Files)
+        {
+          wchar_t Names[NameSize];
+          wchar_t 0;
+        }
+        []
+
+      kAttributes:  (0x15)
+        BYTE AllAreDefined
+        if (AllAreDefined == 0)
+        {
+          for(NumFiles)
+            BIT AttributesAreDefined
+        }
+        BYTE External;
+        if(External != 0)
+          UINT64 DataIndex
+        []
+        for(Definded Attributes)
+          UINT32 Attributes
+        []
+    }
+  }
+
+
+Header
+~~~~~~
+  BYTE NID::kHeader (0x01)
+
+  []
+  ArchiveProperties
+  []
+
+  []
+  BYTE NID::kAdditionalStreamsInfo; (0x03)
+  StreamsInfo
+  []
+
+  []
+  BYTE NID::kMainStreamsInfo;    (0x04)
+  StreamsInfo
+  []
+
+  []
+  FilesInfo
+  []
+
+  BYTE NID::kEnd
+
+
+HeaderInfo
+~~~~~~~~~~
+  []
+  BYTE NID::kEncodedHeader; (0x17)
+  StreamsInfo for Encoded Header
+  []
+
+
+---
+End of document

+ 32 - 0
lzma/C/7zCrc.c

@@ -0,0 +1,32 @@
+/* 7zCrc.c */
+
+#include "7zCrc.h"
+
+#define kCrcPoly 0xEDB88320
+UInt32 g_CrcTable[256];
+
+void MY_FAST_CALL CrcGenerateTable(void)
+{
+  UInt32 i;
+  for (i = 0; i < 256; i++)
+  {
+    UInt32 r = i;
+    int j;
+    for (j = 0; j < 8; j++)
+      r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
+    g_CrcTable[i] = r;
+  }
+}
+
+UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
+{
+  const Byte *p = (const Byte *)data;
+  for (; size > 0 ; size--, p++) 
+    v = CRC_UPDATE_BYTE(v, *p);
+  return v;
+}
+
+UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
+{
+  return CrcUpdate(CRC_INIT_VAL, data, size) ^ 0xFFFFFFFF;
+}

+ 21 - 0
lzma/C/7zCrc.h

@@ -0,0 +1,21 @@
+/* 7zCrc.h */
+
+#ifndef __7Z_CRC_H
+#define __7Z_CRC_H
+
+#include <stddef.h>
+
+#include "Types.h"
+
+extern UInt32 g_CrcTable[];
+
+void MY_FAST_CALL CrcGenerateTable(void);
+
+#define CRC_INIT_VAL 0xFFFFFFFF
+#define CRC_GET_DIGEST(crc) ((crc) ^ 0xFFFFFFFF)
+#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size);
+UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size);
+
+#endif

+ 40 - 0
lzma/C/7zCrcT8.c

@@ -0,0 +1,40 @@
+/* 7zCrcT8.c */
+
+#include "7zCrc.h"
+
+#define kCrcPoly 0xEDB88320
+#define CRC_NUM_TABLES 8
+
+UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
+
+void MY_FAST_CALL CrcGenerateTable()
+{
+  UInt32 i;
+  for (i = 0; i < 256; i++)
+  {
+    UInt32 r = i;
+    int j;
+    for (j = 0; j < 8; j++)
+      r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
+    g_CrcTable[i] = r;
+  }
+  #if CRC_NUM_TABLES > 1
+  for (; i < 256 * CRC_NUM_TABLES; i++)
+  {
+    UInt32 r = g_CrcTable[i - 256];
+    g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
+  }
+  #endif
+}
+
+UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
+
+UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
+{
+  return CrcUpdateT8(v, data, size, g_CrcTable);
+}
+
+UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
+{
+  return CrcUpdateT8(CRC_INIT_VAL, data, size, g_CrcTable) ^ 0xFFFFFFFF;
+}

+ 119 - 0
lzma/C/Alloc.c

@@ -0,0 +1,119 @@
+/* Alloc.c */
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#include <stdlib.h>
+
+#include "Alloc.h"
+
+/* #define _SZ_ALLOC_DEBUG */
+
+/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
+#ifdef _SZ_ALLOC_DEBUG
+#include <stdio.h>
+int g_allocCount = 0;
+int g_allocCountMid = 0;
+int g_allocCountBig = 0;
+#endif
+
+void *MyAlloc(size_t size)
+{
+  if (size == 0)
+    return 0;
+  #ifdef _SZ_ALLOC_DEBUG
+  fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount++);
+  #endif
+  return malloc(size);
+}
+
+void MyFree(void *address)
+{
+  #ifdef _SZ_ALLOC_DEBUG
+  if (address != 0)
+    fprintf(stderr, "\nFree; count = %10d", --g_allocCount);
+  #endif
+  free(address);
+}
+
+#ifdef _WIN32
+
+void *MidAlloc(size_t size)
+{
+  if (size == 0)
+    return 0;
+  #ifdef _SZ_ALLOC_DEBUG
+  fprintf(stderr, "\nAlloc_Mid %10d bytes;  count = %10d", size, g_allocCountMid++);
+  #endif
+  return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
+}
+
+void MidFree(void *address)
+{
+  #ifdef _SZ_ALLOC_DEBUG
+  if (address != 0)
+    fprintf(stderr, "\nFree_Mid; count = %10d", --g_allocCountMid);
+  #endif
+  if (address == 0)
+    return;
+  VirtualFree(address, 0, MEM_RELEASE);
+}
+
+#ifndef MEM_LARGE_PAGES
+#undef _7ZIP_LARGE_PAGES
+#endif
+
+#ifdef _7ZIP_LARGE_PAGES
+SIZE_T g_LargePageSize = 0;
+typedef SIZE_T (WINAPI *GetLargePageMinimumP)();
+#endif
+
+void SetLargePageSize()
+{
+  #ifdef _7ZIP_LARGE_PAGES
+  SIZE_T size = 0;
+  GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP)
+        GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum");
+  if (largePageMinimum == 0)
+    return;
+  size = largePageMinimum();
+  if (size == 0 || (size & (size - 1)) != 0)
+    return;
+  g_LargePageSize = size;
+  #endif
+}
+
+
+void *BigAlloc(size_t size)
+{
+  if (size == 0)
+    return 0;
+  #ifdef _SZ_ALLOC_DEBUG
+  fprintf(stderr, "\nAlloc_Big %10d bytes;  count = %10d", size, g_allocCountBig++);
+  #endif
+  
+  #ifdef _7ZIP_LARGE_PAGES
+  if (g_LargePageSize != 0 && g_LargePageSize <= (1 << 30) && size >= (1 << 18))
+  {
+    void *res = VirtualAlloc(0, (size + g_LargePageSize - 1) & (~(g_LargePageSize - 1)), 
+        MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
+    if (res != 0)
+      return res;
+  }
+  #endif
+  return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
+}
+
+void BigFree(void *address)
+{
+  #ifdef _SZ_ALLOC_DEBUG
+  if (address != 0)
+    fprintf(stderr, "\nFree_Big; count = %10d", --g_allocCountBig);
+  #endif
+  
+  if (address == 0)
+    return;
+  VirtualFree(address, 0, MEM_RELEASE);
+}
+
+#endif

+ 29 - 0
lzma/C/Alloc.h

@@ -0,0 +1,29 @@
+/* Alloc.h */
+
+#ifndef __COMMON_ALLOC_H
+#define __COMMON_ALLOC_H
+
+#include <stddef.h>
+
+void *MyAlloc(size_t size);
+void MyFree(void *address);
+
+#ifdef _WIN32
+
+void SetLargePageSize();
+
+void *MidAlloc(size_t size);
+void MidFree(void *address);
+void *BigAlloc(size_t size);
+void BigFree(void *address);
+
+#else
+
+#define MidAlloc(size) MyAlloc(size)
+#define MidFree(address) MyFree(address)
+#define BigAlloc(size) MyAlloc(size)
+#define BigFree(address) MyFree(address)
+
+#endif
+
+#endif

+ 70 - 0
lzma/C/Archive/7z/7zAlloc.c

@@ -0,0 +1,70 @@
+/* 7zAlloc.c */
+
+#include <stdlib.h>
+#include "7zAlloc.h"
+
+/* #define _SZ_ALLOC_DEBUG */
+/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
+
+#ifdef _SZ_ALLOC_DEBUG
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#include <stdio.h>
+int g_allocCount = 0;
+int g_allocCountTemp = 0;
+#endif
+
+void *SzAlloc(size_t size)
+{
+  if (size == 0)
+    return 0;
+  #ifdef _SZ_ALLOC_DEBUG
+  fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount);
+  g_allocCount++;
+  #endif
+  return malloc(size);
+}
+
+void SzFree(void *address)
+{
+  #ifdef _SZ_ALLOC_DEBUG
+  if (address != 0)
+  {
+    g_allocCount--;
+    fprintf(stderr, "\nFree; count = %10d", g_allocCount);
+  }
+  #endif
+  free(address);
+}
+
+void *SzAllocTemp(size_t size)
+{
+  if (size == 0)
+    return 0;
+  #ifdef _SZ_ALLOC_DEBUG
+  fprintf(stderr, "\nAlloc_temp %10d bytes;  count = %10d", size, g_allocCountTemp);
+  g_allocCountTemp++;
+  #ifdef _WIN32
+  return HeapAlloc(GetProcessHeap(), 0, size);
+  #endif
+  #endif
+  return malloc(size);
+}
+
+void SzFreeTemp(void *address)
+{
+  #ifdef _SZ_ALLOC_DEBUG
+  if (address != 0)
+  {
+    g_allocCountTemp--;
+    fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp);
+  }
+  #ifdef _WIN32
+  HeapFree(GetProcessHeap(), 0, address);
+  return;
+  #endif
+  #endif
+  free(address);
+}

+ 20 - 0
lzma/C/Archive/7z/7zAlloc.h

@@ -0,0 +1,20 @@
+/* 7zAlloc.h */
+
+#ifndef __7Z_ALLOC_H
+#define __7Z_ALLOC_H
+
+#include <stddef.h>
+
+typedef struct _ISzAlloc
+{
+  void *(*Alloc)(size_t size);
+  void (*Free)(void *address); /* address can be 0 */
+} ISzAlloc;
+
+void *SzAlloc(size_t size);
+void SzFree(void *address);
+
+void *SzAllocTemp(size_t size);
+void SzFreeTemp(void *address);
+
+#endif

+ 29 - 0
lzma/C/Archive/7z/7zBuffer.c

@@ -0,0 +1,29 @@
+/* 7zBuffer.c */
+
+#include "7zBuffer.h"
+#include "7zAlloc.h"
+
+void SzByteBufferInit(CSzByteBuffer *buffer)
+{
+  buffer->Capacity = 0;
+  buffer->Items = 0;
+}
+
+int SzByteBufferCreate(CSzByteBuffer *buffer, size_t newCapacity, void * (*allocFunc)(size_t size))
+{
+  buffer->Capacity = newCapacity;
+  if (newCapacity == 0)
+  {
+    buffer->Items = 0;
+    return 1;
+  }
+  buffer->Items = (Byte *)allocFunc(newCapacity);
+  return (buffer->Items != 0);
+}
+
+void SzByteBufferFree(CSzByteBuffer *buffer, void (*freeFunc)(void *))
+{
+  freeFunc(buffer->Items);
+  buffer->Items = 0;
+  buffer->Capacity = 0;
+}

+ 19 - 0
lzma/C/Archive/7z/7zBuffer.h

@@ -0,0 +1,19 @@
+/* 7zBuffer.h */
+
+#ifndef __7Z_BUFFER_H
+#define __7Z_BUFFER_H
+
+#include <stddef.h>
+#include "../../Types.h"
+
+typedef struct _CSzByteBuffer
+{
+  size_t Capacity;
+  Byte *Items;
+}CSzByteBuffer;
+
+void SzByteBufferInit(CSzByteBuffer *buffer);
+int SzByteBufferCreate(CSzByteBuffer *buffer, size_t newCapacity, void * (*allocFunc)(size_t size));
+void SzByteBufferFree(CSzByteBuffer *buffer, void (*freeFunc)(void *));
+
+#endif

+ 341 - 0
lzma/C/Archive/7z/7zDecode.c

@@ -0,0 +1,341 @@
+/* 7zDecode.c */
+
+#include <memory.h>
+
+#include "7zDecode.h"
+#ifdef _SZ_ONE_DIRECTORY
+#include "LzmaDecode.h"
+#else
+#include "../../Compress/Lzma/LzmaDecode.h"
+#include "../../Compress/Branch/BranchX86.h"
+#include "../../Compress/Branch/BranchX86_2.h"
+#endif
+
+#define k_Copy 0
+#define k_LZMA 0x30101
+#define k_BCJ 0x03030103
+#define k_BCJ2 0x0303011B
+
+#ifdef _LZMA_IN_CB
+
+typedef struct _CLzmaInCallbackImp
+{
+  ILzmaInCallback InCallback;
+  ISzInStream *InStream;
+  CFileSize Size;
+} CLzmaInCallbackImp;
+
+int LzmaReadImp(void *object, const unsigned char **buffer, SizeT *size)
+{
+  CLzmaInCallbackImp *cb = (CLzmaInCallbackImp *)object;
+  size_t processedSize;
+  SZ_RESULT res;
+  size_t curSize = (1 << 20);
+  if (curSize > cb->Size)
+    curSize = (size_t)cb->Size;
+  *size = 0;
+  res = cb->InStream->Read((void *)cb->InStream, (void **)buffer, curSize, &processedSize);
+  *size = (SizeT)processedSize;
+  if (processedSize > curSize)
+    return (int)SZE_FAIL;
+  cb->Size -= processedSize;
+  if (res == SZ_OK)
+    return 0;
+  return (int)res;
+}
+
+#endif
+
+SZ_RESULT SzDecodeLzma(CCoderInfo *coder, CFileSize inSize,
+    #ifdef _LZMA_IN_CB
+    ISzInStream *inStream,
+    #else
+    const Byte *inBuffer,
+    #endif
+    Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
+{
+  #ifdef _LZMA_IN_CB
+  CLzmaInCallbackImp lzmaCallback;
+  #else
+  SizeT inProcessed;
+  #endif
+  
+  CLzmaDecoderState state;  /* it's about 24-80 bytes structure, if int is 32-bit */
+  int result;
+  SizeT outSizeProcessedLoc;
+  
+  #ifdef _LZMA_IN_CB
+  lzmaCallback.Size = inSize;
+  lzmaCallback.InStream = inStream;
+  lzmaCallback.InCallback.Read = LzmaReadImp;
+  #endif
+  
+  if (LzmaDecodeProperties(&state.Properties, coder->Properties.Items, 
+      (unsigned)coder->Properties.Capacity) != LZMA_RESULT_OK)
+    return SZE_FAIL;
+  
+  state.Probs = (CProb *)allocMain->Alloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
+  if (state.Probs == 0)
+    return SZE_OUTOFMEMORY;
+  
+  #ifdef _LZMA_OUT_READ
+  if (state.Properties.DictionarySize == 0)
+    state.Dictionary = 0;
+  else
+  {
+    state.Dictionary = (unsigned char *)allocMain->Alloc(state.Properties.DictionarySize);
+    if (state.Dictionary == 0)
+    {
+      allocMain->Free(state.Probs);
+      return SZE_OUTOFMEMORY;
+    }
+  }
+  LzmaDecoderInit(&state);
+  #endif
+  
+  result = LzmaDecode(&state,
+  #ifdef _LZMA_IN_CB
+    &lzmaCallback.InCallback,
+  #else
+    inBuffer, (SizeT)inSize, &inProcessed,
+  #endif
+    outBuffer, (SizeT)outSize, &outSizeProcessedLoc);
+  allocMain->Free(state.Probs);
+  #ifdef _LZMA_OUT_READ
+  allocMain->Free(state.Dictionary);
+  #endif
+  if (result == LZMA_RESULT_DATA_ERROR)
+    return SZE_DATA_ERROR;
+  if (result != LZMA_RESULT_OK)
+    return SZE_FAIL;
+  return (outSizeProcessedLoc == outSize) ? SZ_OK : SZE_DATA_ERROR;
+}
+
+#ifdef _LZMA_IN_CB
+SZ_RESULT SzDecodeCopy(CFileSize inSize, ISzInStream *inStream, Byte *outBuffer)
+{
+  while (inSize > 0)
+  {
+    void *inBuffer;
+    size_t processedSize, curSize = (1 << 18);
+    if (curSize > inSize)
+      curSize = (size_t)(inSize);
+    RINOK(inStream->Read((void *)inStream, (void **)&inBuffer, curSize, &processedSize));
+    if (processedSize == 0)
+      return SZE_DATA_ERROR;
+    if (processedSize > curSize)
+      return SZE_FAIL;
+    memcpy(outBuffer, inBuffer, processedSize);
+    outBuffer += processedSize;
+    inSize -= processedSize;
+  }
+  return SZ_OK;
+}
+#endif
+
+#define IS_UNSUPPORTED_METHOD(m) ((m) != k_Copy && (m) != k_LZMA)
+#define IS_UNSUPPORTED_CODER(c) (IS_UNSUPPORTED_METHOD(c.MethodID) || c.NumInStreams != 1 || c.NumOutStreams != 1)
+#define IS_NO_BCJ(c) (c.MethodID != k_BCJ || c.NumInStreams != 1 || c.NumOutStreams != 1)
+#define IS_NO_BCJ2(c) (c.MethodID != k_BCJ2 || c.NumInStreams != 4 || c.NumOutStreams != 1)
+
+SZ_RESULT CheckSupportedFolder(const CFolder *f)
+{
+  if (f->NumCoders < 1 || f->NumCoders > 4)
+    return SZE_NOTIMPL;
+  if (IS_UNSUPPORTED_CODER(f->Coders[0]))
+    return SZE_NOTIMPL;
+  if (f->NumCoders == 1)
+  {
+    if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
+      return SZE_NOTIMPL;
+    return SZ_OK;
+  }
+  if (f->NumCoders == 2)
+  {
+    if (IS_NO_BCJ(f->Coders[1]) ||
+        f->NumPackStreams != 1 || f->PackStreams[0] != 0 ||
+        f->NumBindPairs != 1 ||
+        f->BindPairs[0].InIndex != 1 || f->BindPairs[0].OutIndex != 0)
+      return SZE_NOTIMPL;
+    return SZ_OK;
+  }
+  if (f->NumCoders == 4)
+  {
+    if (IS_UNSUPPORTED_CODER(f->Coders[1]) ||
+        IS_UNSUPPORTED_CODER(f->Coders[2]) ||
+        IS_NO_BCJ2(f->Coders[3]))
+      return SZE_NOTIMPL;
+    if (f->NumPackStreams != 4 || 
+        f->PackStreams[0] != 2 ||
+        f->PackStreams[1] != 6 ||
+        f->PackStreams[2] != 1 ||
+        f->PackStreams[3] != 0 ||
+        f->NumBindPairs != 3 ||
+        f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
+        f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
+        f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
+      return SZE_NOTIMPL;
+    return SZ_OK;
+  }
+  return SZE_NOTIMPL;
+}
+
+CFileSize GetSum(const CFileSize *values, UInt32 index)
+{
+  CFileSize sum = 0;
+  UInt32 i;
+  for (i = 0; i < index; i++)
+    sum += values[i];
+  return sum;
+}
+
+SZ_RESULT SzDecode2(const CFileSize *packSizes, const CFolder *folder,
+    #ifdef _LZMA_IN_CB
+    ISzInStream *inStream, CFileSize startPos,
+    #else
+    const Byte *inBuffer,
+    #endif
+    Byte *outBuffer, size_t outSize, ISzAlloc *allocMain,
+    Byte *tempBuf[])
+{
+  UInt32 ci;
+  size_t tempSizes[3] = { 0, 0, 0};
+  size_t tempSize3 = 0;
+  Byte *tempBuf3 = 0;
+
+  RINOK(CheckSupportedFolder(folder));
+
+  for (ci = 0; ci < folder->NumCoders; ci++)
+  {
+    CCoderInfo *coder = &folder->Coders[ci];
+
+    if (coder->MethodID == k_Copy || coder->MethodID == k_LZMA)
+    {
+      UInt32 si = 0;
+      CFileSize offset;
+      CFileSize inSize;
+      Byte *outBufCur = outBuffer;
+      size_t outSizeCur = outSize;
+      if (folder->NumCoders == 4)
+      {
+        UInt32 indices[] = { 3, 2, 0 };
+        CFileSize unpackSize = folder->UnPackSizes[ci];
+        si = indices[ci];
+        if (ci < 2)
+        {
+          Byte *temp;
+          outSizeCur = (size_t)unpackSize;
+          if (outSizeCur != unpackSize)
+            return SZE_OUTOFMEMORY;
+          temp = (Byte *)allocMain->Alloc(outSizeCur);
+          if (temp == 0 && outSizeCur != 0)
+            return SZE_OUTOFMEMORY;
+          outBufCur = tempBuf[1 - ci] = temp;
+          tempSizes[1 - ci] = outSizeCur;
+        }
+        else if (ci == 2)
+        {
+          if (unpackSize > outSize)
+            return SZE_OUTOFMEMORY;
+          tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
+          tempSize3 = outSizeCur = (size_t)unpackSize;
+        }
+        else
+          return SZE_NOTIMPL;
+      }
+      offset = GetSum(packSizes, si);
+      inSize = packSizes[si];
+      #ifdef _LZMA_IN_CB
+      RINOK(inStream->Seek(inStream, startPos + offset));
+      #endif
+
+      if (coder->MethodID == k_Copy)
+      {
+        if (inSize != outSizeCur)
+          return SZE_DATA_ERROR;
+        
+        #ifdef _LZMA_IN_CB
+        RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
+        #else
+        memcpy(outBufCur, inBuffer + (size_t)offset, (size_t)inSize);
+        #endif
+      }
+      else
+      {
+        SZ_RESULT res = SzDecodeLzma(coder, inSize,
+            #ifdef _LZMA_IN_CB
+            inStream,
+            #else
+            inBuffer + (size_t)offset,
+            #endif
+            outBufCur, outSizeCur, allocMain);
+        RINOK(res)
+      }
+    }
+    else if (coder->MethodID == k_BCJ)
+    {
+      UInt32 state;
+      if (ci != 1)
+        return SZE_NOTIMPL;
+      x86_Convert_Init(state);
+      x86_Convert(outBuffer, outSize, 0, &state, 0);
+    }
+    else if (coder->MethodID == k_BCJ2)
+    {
+      CFileSize offset = GetSum(packSizes, 1);
+      CFileSize s3Size = packSizes[1];
+      SZ_RESULT res;
+      if (ci != 3)
+        return SZE_NOTIMPL;
+
+      #ifdef _LZMA_IN_CB
+      RINOK(inStream->Seek(inStream, startPos + offset));
+      tempSizes[2] = (size_t)s3Size;
+      if (tempSizes[2] != s3Size)
+        return SZE_OUTOFMEMORY;
+      tempBuf[2] = (Byte *)allocMain->Alloc(tempSizes[2]);
+      if (tempBuf[2] == 0 && tempSizes[2] != 0)
+        return SZE_OUTOFMEMORY;
+      res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
+      RINOK(res)
+      #endif
+
+      res = x86_2_Decode(
+          tempBuf3, tempSize3, 
+          tempBuf[0], tempSizes[0], 
+          tempBuf[1], tempSizes[1], 
+          #ifdef _LZMA_IN_CB
+          tempBuf[2], tempSizes[2], 
+          #else
+          inBuffer + (size_t)offset, (size_t)s3Size, 
+          #endif
+          outBuffer, outSize);
+      RINOK(res)
+    }
+    else 
+      return SZE_NOTIMPL;
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzDecode(const CFileSize *packSizes, const CFolder *folder,
+    #ifdef _LZMA_IN_CB
+    ISzInStream *inStream, CFileSize startPos,
+    #else
+    const Byte *inBuffer,
+    #endif
+    Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
+{
+  Byte *tempBuf[3] = { 0, 0, 0};
+  int i;
+  SZ_RESULT res = SzDecode2(packSizes, folder,
+      #ifdef _LZMA_IN_CB
+      inStream, startPos,
+      #else
+      inBuffer,
+      #endif
+      outBuffer, outSize, allocMain, tempBuf);
+  for (i = 0; i < 3; i++)
+    allocMain->Free(tempBuf[i]);
+  return res;
+}

+ 20 - 0
lzma/C/Archive/7z/7zDecode.h

@@ -0,0 +1,20 @@
+/* 7zDecode.h */
+
+#ifndef __7Z_DECODE_H
+#define __7Z_DECODE_H
+
+#include "7zItem.h"
+#include "7zAlloc.h"
+#ifdef _LZMA_IN_CB
+#include "7zIn.h"
+#endif
+
+SZ_RESULT SzDecode(const CFileSize *packSizes, const CFolder *folder,
+    #ifdef _LZMA_IN_CB
+    ISzInStream *stream, CFileSize startPos,
+    #else
+    const Byte *inBuffer,
+    #endif
+    Byte *outBuffer, size_t outSize, ISzAlloc *allocMain);
+
+#endif

+ 119 - 0
lzma/C/Archive/7z/7zExtract.c

@@ -0,0 +1,119 @@
+/* 7zExtract.c */
+
+#include "7zExtract.h"
+#include "7zDecode.h"
+#include "../../7zCrc.h"
+
+SZ_RESULT SzExtract(
+    ISzInStream *inStream, 
+    CArchiveDatabaseEx *db,
+    UInt32 fileIndex,
+    UInt32 *blockIndex,
+    Byte **outBuffer, 
+    size_t *outBufferSize,
+    size_t *offset, 
+    size_t *outSizeProcessed, 
+    ISzAlloc *allocMain,
+    ISzAlloc *allocTemp)
+{
+  UInt32 folderIndex = db->FileIndexToFolderIndexMap[fileIndex];
+  SZ_RESULT res = SZ_OK;
+  *offset = 0;
+  *outSizeProcessed = 0;
+  if (folderIndex == (UInt32)-1)
+  {
+    allocMain->Free(*outBuffer);
+    *blockIndex = folderIndex;
+    *outBuffer = 0;
+    *outBufferSize = 0;
+    return SZ_OK;
+  }
+
+  if (*outBuffer == 0 || *blockIndex != folderIndex)
+  {
+    CFolder *folder = db->Database.Folders + folderIndex;
+    CFileSize unPackSizeSpec = SzFolderGetUnPackSize(folder);
+    size_t unPackSize = (size_t)unPackSizeSpec;
+    CFileSize startOffset = SzArDbGetFolderStreamPos(db, folderIndex, 0);
+    #ifndef _LZMA_IN_CB
+    Byte *inBuffer = 0;
+    size_t processedSize;
+    CFileSize packSizeSpec;
+    size_t packSize;
+    RINOK(SzArDbGetFolderFullPackSize(db, folderIndex, &packSizeSpec));
+    packSize = (size_t)packSizeSpec;
+    if (packSize != packSizeSpec)
+      return SZE_OUTOFMEMORY;
+    #endif
+    if (unPackSize != unPackSizeSpec)
+      return SZE_OUTOFMEMORY;
+    *blockIndex = folderIndex;
+    allocMain->Free(*outBuffer);
+    *outBuffer = 0;
+    
+    RINOK(inStream->Seek(inStream, startOffset));
+    
+    #ifndef _LZMA_IN_CB
+    if (packSize != 0)
+    {
+      inBuffer = (Byte *)allocTemp->Alloc(packSize);
+      if (inBuffer == 0)
+        return SZE_OUTOFMEMORY;
+    }
+    res = inStream->Read(inStream, inBuffer, packSize, &processedSize);
+    if (res == SZ_OK && processedSize != packSize)
+      res = SZE_FAIL;
+    #endif
+    if (res == SZ_OK)
+    {
+      *outBufferSize = unPackSize;
+      if (unPackSize != 0)
+      {
+        *outBuffer = (Byte *)allocMain->Alloc(unPackSize);
+        if (*outBuffer == 0)
+          res = SZE_OUTOFMEMORY;
+      }
+      if (res == SZ_OK)
+      {
+        res = SzDecode(db->Database.PackSizes + 
+          db->FolderStartPackStreamIndex[folderIndex], folder, 
+          #ifdef _LZMA_IN_CB
+          inStream, startOffset, 
+          #else
+          inBuffer, 
+          #endif
+          *outBuffer, unPackSize, allocTemp);
+        if (res == SZ_OK)
+        {
+          if (folder->UnPackCRCDefined)
+          {
+            if (CrcCalc(*outBuffer, unPackSize) != folder->UnPackCRC)
+              res = SZE_CRC_ERROR;
+          }
+        }
+      }
+    }
+    #ifndef _LZMA_IN_CB
+    allocTemp->Free(inBuffer);
+    #endif
+  }
+  if (res == SZ_OK)
+  {
+    UInt32 i; 
+    CFileItem *fileItem = db->Database.Files + fileIndex;
+    *offset = 0;
+    for(i = db->FolderStartFileIndex[folderIndex]; i < fileIndex; i++)
+      *offset += (UInt32)db->Database.Files[i].Size;
+    *outSizeProcessed = (size_t)fileItem->Size;
+    if (*offset + *outSizeProcessed > *outBufferSize)
+      return SZE_FAIL;
+    {
+      if (fileItem->IsFileCRCDefined)
+      {
+        if (CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->FileCRC)
+          res = SZE_CRC_ERROR;
+      }
+    }
+  }
+  return res;
+}

+ 40 - 0
lzma/C/Archive/7z/7zExtract.h

@@ -0,0 +1,40 @@
+/* 7zExtract.h */
+
+#ifndef __7Z_EXTRACT_H
+#define __7Z_EXTRACT_H
+
+#include "7zIn.h"
+
+/*
+  SzExtract extracts file from archive
+
+  *outBuffer must be 0 before first call for each new archive. 
+
+  Extracting cache:
+    If you need to decompress more than one file, you can send 
+    these values from previous call:
+      *blockIndex, 
+      *outBuffer, 
+      *outBufferSize
+    You can consider "*outBuffer" as cache of solid block. If your archive is solid, 
+    it will increase decompression speed.
+  
+    If you use external function, you can declare these 3 cache variables 
+    (blockIndex, outBuffer, outBufferSize) as static in that external function.
+    
+    Free *outBuffer and set *outBuffer to 0, if you want to flush cache.
+*/
+
+SZ_RESULT SzExtract(
+    ISzInStream *inStream, 
+    CArchiveDatabaseEx *db,
+    UInt32 fileIndex,         /* index of file */
+    UInt32 *blockIndex,       /* index of solid block */
+    Byte **outBuffer,         /* pointer to pointer to output buffer (allocated with allocMain) */
+    size_t *outBufferSize,    /* buffer size for output buffer */
+    size_t *offset,           /* offset of stream for required file in *outBuffer */
+    size_t *outSizeProcessed, /* size of file in *outBuffer */
+    ISzAlloc *allocMain,
+    ISzAlloc *allocTemp);
+
+#endif

+ 5 - 0
lzma/C/Archive/7z/7zHeader.c

@@ -0,0 +1,5 @@
+/*  7zHeader.c */
+
+#include "7zHeader.h"
+
+Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};

+ 55 - 0
lzma/C/Archive/7z/7zHeader.h

@@ -0,0 +1,55 @@
+/* 7zHeader.h */
+
+#ifndef __7Z_HEADER_H
+#define __7Z_HEADER_H
+
+#include "../../Types.h"
+
+#define k7zSignatureSize 6
+extern Byte k7zSignature[k7zSignatureSize];
+
+#define k7zMajorVersion 0
+
+#define k7zStartHeaderSize 0x20
+
+enum EIdEnum
+{
+  k7zIdEnd,
+    
+  k7zIdHeader,
+    
+  k7zIdArchiveProperties,
+    
+  k7zIdAdditionalStreamsInfo,
+  k7zIdMainStreamsInfo,
+  k7zIdFilesInfo,
+  
+  k7zIdPackInfo,
+  k7zIdUnPackInfo,
+  k7zIdSubStreamsInfo,
+  
+  k7zIdSize,
+  k7zIdCRC,
+  
+  k7zIdFolder,
+  
+  k7zIdCodersUnPackSize,
+  k7zIdNumUnPackStream,
+  
+  k7zIdEmptyStream,
+  k7zIdEmptyFile,
+  k7zIdAnti,
+  
+  k7zIdName,
+  k7zIdCreationTime,
+  k7zIdLastAccessTime,
+  k7zIdLastWriteTime,
+  k7zIdWinAttributes,
+  k7zIdComment,
+  
+  k7zIdEncodedHeader,
+  
+  k7zIdStartPos
+};
+
+#endif

+ 1314 - 0
lzma/C/Archive/7z/7zIn.c

@@ -0,0 +1,1314 @@
+/* 7zIn.c */
+
+#include "7zIn.h"
+#include "7zDecode.h"
+#include "../../7zCrc.h"
+
+#define RINOM(x) { if((x) == 0) return SZE_OUTOFMEMORY; }
+
+void SzArDbExInit(CArchiveDatabaseEx *db)
+{
+  SzArchiveDatabaseInit(&db->Database);
+  db->FolderStartPackStreamIndex = 0;
+  db->PackStreamStartPositions = 0;
+  db->FolderStartFileIndex = 0;
+  db->FileIndexToFolderIndexMap = 0;
+}
+
+void SzArDbExFree(CArchiveDatabaseEx *db, void (*freeFunc)(void *))
+{
+  freeFunc(db->FolderStartPackStreamIndex);
+  freeFunc(db->PackStreamStartPositions);
+  freeFunc(db->FolderStartFileIndex);
+  freeFunc(db->FileIndexToFolderIndexMap);
+  SzArchiveDatabaseFree(&db->Database, freeFunc);
+  SzArDbExInit(db);
+}
+
+/*
+CFileSize GetFolderPackStreamSize(int folderIndex, int streamIndex) const 
+{
+  return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex];
+}
+
+CFileSize GetFilePackSize(int fileIndex) const
+{
+  int folderIndex = FileIndexToFolderIndexMap[fileIndex];
+  if (folderIndex >= 0)
+  {
+    const CFolder &folderInfo = Folders[folderIndex];
+    if (FolderStartFileIndex[folderIndex] == fileIndex)
+    return GetFolderFullPackSize(folderIndex);
+  }
+  return 0;
+}
+*/
+
+#define MY_ALLOC(T, p, size, allocFunc) { if ((size) == 0) p = 0; else \
+  if ((p = (T *)allocFunc((size) * sizeof(T))) == 0) return SZE_OUTOFMEMORY; }
+
+SZ_RESULT SzArDbExFill(CArchiveDatabaseEx *db, void * (*allocFunc)(size_t size))
+{
+  UInt32 startPos = 0;
+  CFileSize startPosSize = 0;
+  UInt32 i;
+  UInt32 folderIndex = 0;
+  UInt32 indexInFolder = 0;
+  MY_ALLOC(UInt32, db->FolderStartPackStreamIndex, db->Database.NumFolders, allocFunc);
+  for(i = 0; i < db->Database.NumFolders; i++)
+  {
+    db->FolderStartPackStreamIndex[i] = startPos;
+    startPos += db->Database.Folders[i].NumPackStreams;
+  }
+
+  MY_ALLOC(CFileSize, db->PackStreamStartPositions, db->Database.NumPackStreams, allocFunc);
+
+  for(i = 0; i < db->Database.NumPackStreams; i++)
+  {
+    db->PackStreamStartPositions[i] = startPosSize;
+    startPosSize += db->Database.PackSizes[i];
+  }
+
+  MY_ALLOC(UInt32, db->FolderStartFileIndex, db->Database.NumFolders, allocFunc);
+  MY_ALLOC(UInt32, db->FileIndexToFolderIndexMap, db->Database.NumFiles, allocFunc);
+
+  for (i = 0; i < db->Database.NumFiles; i++)
+  {
+    CFileItem *file = db->Database.Files + i;
+    int emptyStream = !file->HasStream;
+    if (emptyStream && indexInFolder == 0)
+    {
+      db->FileIndexToFolderIndexMap[i] = (UInt32)-1;
+      continue;
+    }
+    if (indexInFolder == 0)
+    {
+      /*
+      v3.13 incorrectly worked with empty folders
+      v4.07: Loop for skipping empty folders
+      */
+      for (;;)
+      {
+        if (folderIndex >= db->Database.NumFolders)
+          return SZE_ARCHIVE_ERROR;
+        db->FolderStartFileIndex[folderIndex] = i;
+        if (db->Database.Folders[folderIndex].NumUnPackStreams != 0)
+          break;
+        folderIndex++;
+      }
+    }
+    db->FileIndexToFolderIndexMap[i] = folderIndex;
+    if (emptyStream)
+      continue;
+    indexInFolder++;
+    if (indexInFolder >= db->Database.Folders[folderIndex].NumUnPackStreams)
+    {
+      folderIndex++;
+      indexInFolder = 0;
+    }
+  }
+  return SZ_OK;
+}
+
+
+CFileSize SzArDbGetFolderStreamPos(CArchiveDatabaseEx *db, UInt32 folderIndex, UInt32 indexInFolder)
+{
+  return db->ArchiveInfo.DataStartPosition + 
+    db->PackStreamStartPositions[db->FolderStartPackStreamIndex[folderIndex] + indexInFolder];
+}
+
+int SzArDbGetFolderFullPackSize(CArchiveDatabaseEx *db, UInt32 folderIndex, CFileSize *resSize)
+{
+  UInt32 packStreamIndex = db->FolderStartPackStreamIndex[folderIndex];
+  CFolder *folder = db->Database.Folders + folderIndex;
+  CFileSize size = 0;
+  UInt32 i;
+  for (i = 0; i < folder->NumPackStreams; i++)
+  {
+    CFileSize t = size + db->Database.PackSizes[packStreamIndex + i];
+    if (t < size)
+      return SZE_FAIL;
+    size = t;
+  }
+  *resSize = size;
+  return SZ_OK;
+}
+
+
+/*
+SZ_RESULT SzReadTime(const CObjectVector<CSzByteBuffer> &dataVector,
+    CObjectVector<CFileItem> &files, UInt64 type)
+{
+  CBoolVector boolVector;
+  RINOK(ReadBoolVector2(files.Size(), boolVector))
+
+  CStreamSwitch streamSwitch;
+  RINOK(streamSwitch.Set(this, &dataVector));
+
+  for(int i = 0; i < files.Size(); i++)
+  {
+    CFileItem &file = files[i];
+    CArchiveFileTime fileTime;
+    bool defined = boolVector[i];
+    if (defined)
+    {
+      UInt32 low, high;
+      RINOK(SzReadUInt32(low));
+      RINOK(SzReadUInt32(high));
+      fileTime.dwLowDateTime = low;
+      fileTime.dwHighDateTime = high;
+    }
+    switch(type)
+    {
+      case k7zIdCreationTime:
+        file.IsCreationTimeDefined = defined;
+        if (defined)
+          file.CreationTime = fileTime;
+        break;
+      case k7zIdLastWriteTime:
+        file.IsLastWriteTimeDefined = defined;
+        if (defined)
+          file.LastWriteTime = fileTime;
+        break;
+      case k7zIdLastAccessTime:
+        file.IsLastAccessTimeDefined = defined;
+        if (defined)
+          file.LastAccessTime = fileTime;
+        break;
+    }
+  }
+  return SZ_OK;
+}
+*/
+
+SZ_RESULT SafeReadDirect(ISzInStream *inStream, Byte *data, size_t size)
+{
+  #ifdef _LZMA_IN_CB
+  while (size > 0)
+  {
+    void *inBufferSpec;
+    size_t processedSize;
+    const Byte *inBuffer;
+    RINOK(inStream->Read(inStream, (void **)&inBufferSpec, size, &processedSize));
+    inBuffer = (const Byte *)inBufferSpec;
+    if (processedSize == 0 || processedSize > size)
+      return SZE_FAIL;
+    size -= processedSize;
+    do
+    {
+      *data++ = *inBuffer++;
+    }
+    while (--processedSize != 0);
+  }
+  #else
+  size_t processedSize;
+  RINOK(inStream->Read(inStream, data, size, &processedSize));
+  if (processedSize != size)
+    return SZE_FAIL;
+  #endif
+  return SZ_OK;
+}
+
+SZ_RESULT SafeReadDirectByte(ISzInStream *inStream, Byte *data)
+{
+  return SafeReadDirect(inStream, data, 1);
+}
+
+SZ_RESULT SafeReadDirectUInt32(ISzInStream *inStream, UInt32 *value, UInt32 *crc)
+{
+  int i;
+  *value = 0;
+  for (i = 0; i < 4; i++)
+  {
+    Byte b;
+    RINOK(SafeReadDirectByte(inStream, &b));
+    *value |= ((UInt32)b << (8 * i));
+    *crc = CRC_UPDATE_BYTE(*crc, b);
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SafeReadDirectUInt64(ISzInStream *inStream, UInt64 *value, UInt32 *crc)
+{
+  int i;
+  *value = 0;
+  for (i = 0; i < 8; i++)
+  {
+    Byte b;
+    RINOK(SafeReadDirectByte(inStream, &b));
+    *value |= ((UInt64)b << (8 * i));
+    *crc = CRC_UPDATE_BYTE(*crc, b);
+  }
+  return SZ_OK;
+}
+
+int TestSignatureCandidate(Byte *testBytes)
+{
+  size_t i;
+  for (i = 0; i < k7zSignatureSize; i++)
+    if (testBytes[i] != k7zSignature[i])
+      return 0;
+  return 1;
+}
+
+typedef struct _CSzState
+{
+  Byte *Data;
+  size_t Size;
+}CSzData;
+
+SZ_RESULT SzReadByte(CSzData *sd, Byte *b)
+{
+  if (sd->Size == 0)
+    return SZE_ARCHIVE_ERROR;
+  sd->Size--;
+  *b = *sd->Data++;
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadBytes(CSzData *sd, Byte *data, size_t size)
+{
+  size_t i;
+  for (i = 0; i < size; i++)
+  {
+    RINOK(SzReadByte(sd, data + i));
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadUInt32(CSzData *sd, UInt32 *value)
+{
+  int i;
+  *value = 0;
+  for (i = 0; i < 4; i++)
+  {
+    Byte b;
+    RINOK(SzReadByte(sd, &b));
+    *value |= ((UInt32)(b) << (8 * i));
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadNumber(CSzData *sd, UInt64 *value)
+{
+  Byte firstByte;
+  Byte mask = 0x80;
+  int i;
+  RINOK(SzReadByte(sd, &firstByte));
+  *value = 0;
+  for (i = 0; i < 8; i++)
+  {
+    Byte b;
+    if ((firstByte & mask) == 0)
+    {
+      UInt64 highPart = firstByte & (mask - 1);
+      *value += (highPart << (8 * i));
+      return SZ_OK;
+    }
+    RINOK(SzReadByte(sd, &b));
+    *value |= ((UInt64)b << (8 * i));
+    mask >>= 1;
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadSize(CSzData *sd, CFileSize *value)
+{
+  UInt64 value64;
+  RINOK(SzReadNumber(sd, &value64));
+  *value = (CFileSize)value64;
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadNumber32(CSzData *sd, UInt32 *value)
+{
+  UInt64 value64;
+  RINOK(SzReadNumber(sd, &value64));
+  if (value64 >= 0x80000000)
+    return SZE_NOTIMPL;
+  if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 2)))
+    return SZE_NOTIMPL;
+  *value = (UInt32)value64;
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadID(CSzData *sd, UInt64 *value) 
+{ 
+  return SzReadNumber(sd, value); 
+}
+
+SZ_RESULT SzSkeepDataSize(CSzData *sd, UInt64 size)
+{
+  if (size > sd->Size)
+    return SZE_ARCHIVE_ERROR;
+  sd->Size -= (size_t)size;
+  sd->Data += (size_t)size;
+  return SZ_OK;
+}
+
+SZ_RESULT SzSkeepData(CSzData *sd)
+{
+  UInt64 size;
+  RINOK(SzReadNumber(sd, &size));
+  return SzSkeepDataSize(sd, size);
+}
+
+SZ_RESULT SzReadArchiveProperties(CSzData *sd)
+{
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(SzReadID(sd, &type));
+    if (type == k7zIdEnd)
+      break;
+    SzSkeepData(sd);
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzWaitAttribute(CSzData *sd, UInt64 attribute)
+{
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(SzReadID(sd, &type));
+    if (type == attribute)
+      return SZ_OK;
+    if (type == k7zIdEnd)
+      return SZE_ARCHIVE_ERROR;
+    RINOK(SzSkeepData(sd));
+  }
+}
+
+SZ_RESULT SzReadBoolVector(CSzData *sd, size_t numItems, Byte **v, void * (*allocFunc)(size_t size))
+{
+  Byte b = 0;
+  Byte mask = 0;
+  size_t i;
+  MY_ALLOC(Byte, *v, numItems, allocFunc);
+  for (i = 0; i < numItems; i++)
+  {
+    if (mask == 0)
+    {
+      RINOK(SzReadByte(sd, &b));
+      mask = 0x80;
+    }
+    (*v)[i] = (Byte)(((b & mask) != 0) ? 1 : 0);
+    mask >>= 1;
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadBoolVector2(CSzData *sd, size_t numItems, Byte **v, void * (*allocFunc)(size_t size))
+{
+  Byte allAreDefined;
+  size_t i;
+  RINOK(SzReadByte(sd, &allAreDefined));
+  if (allAreDefined == 0)
+    return SzReadBoolVector(sd, numItems, v, allocFunc);
+  MY_ALLOC(Byte, *v, numItems, allocFunc);
+  for(i = 0; i < numItems; i++)
+    (*v)[i] = 1;
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadHashDigests(
+    CSzData *sd, 
+    size_t numItems,
+    Byte **digestsDefined, 
+    UInt32 **digests, 
+    void * (*allocFunc)(size_t size))
+{
+  size_t i;
+  RINOK(SzReadBoolVector2(sd, numItems, digestsDefined, allocFunc));
+  MY_ALLOC(UInt32, *digests, numItems, allocFunc);
+  for(i = 0; i < numItems; i++)
+    if ((*digestsDefined)[i])
+    {
+      RINOK(SzReadUInt32(sd, (*digests) + i));
+    }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadPackInfo(
+    CSzData *sd, 
+    CFileSize *dataOffset,
+    UInt32 *numPackStreams,
+    CFileSize **packSizes,
+    Byte **packCRCsDefined,
+    UInt32 **packCRCs,
+    void * (*allocFunc)(size_t size))
+{
+  UInt32 i;
+  RINOK(SzReadSize(sd, dataOffset));
+  RINOK(SzReadNumber32(sd, numPackStreams));
+
+  RINOK(SzWaitAttribute(sd, k7zIdSize));
+
+  MY_ALLOC(CFileSize, *packSizes, (size_t)*numPackStreams, allocFunc);
+
+  for(i = 0; i < *numPackStreams; i++)
+  {
+    RINOK(SzReadSize(sd, (*packSizes) + i));
+  }
+
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(SzReadID(sd, &type));
+    if (type == k7zIdEnd)
+      break;
+    if (type == k7zIdCRC)
+    {
+      RINOK(SzReadHashDigests(sd, (size_t)*numPackStreams, packCRCsDefined, packCRCs, allocFunc)); 
+      continue;
+    }
+    RINOK(SzSkeepData(sd));
+  }
+  if (*packCRCsDefined == 0)
+  {
+    MY_ALLOC(Byte, *packCRCsDefined, (size_t)*numPackStreams, allocFunc);
+    MY_ALLOC(UInt32, *packCRCs, (size_t)*numPackStreams, allocFunc);
+    for(i = 0; i < *numPackStreams; i++)
+    {
+      (*packCRCsDefined)[i] = 0;
+      (*packCRCs)[i] = 0;
+    }
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadSwitch(CSzData *sd)
+{
+  Byte external;
+  RINOK(SzReadByte(sd, &external));
+  return (external == 0) ? SZ_OK: SZE_ARCHIVE_ERROR;
+}
+
+SZ_RESULT SzGetNextFolderItem(CSzData *sd, CFolder *folder, void * (*allocFunc)(size_t size))
+{
+  UInt32 numCoders;
+  UInt32 numBindPairs;
+  UInt32 numPackedStreams;
+  UInt32 i;
+  UInt32 numInStreams = 0;
+  UInt32 numOutStreams = 0;
+  RINOK(SzReadNumber32(sd, &numCoders));
+  folder->NumCoders = numCoders;
+
+  MY_ALLOC(CCoderInfo, folder->Coders, (size_t)numCoders, allocFunc);
+
+  for (i = 0; i < numCoders; i++)
+    SzCoderInfoInit(folder->Coders + i);
+
+  for (i = 0; i < numCoders; i++)
+  {
+    Byte mainByte;
+    CCoderInfo *coder = folder->Coders + i;
+    {
+      unsigned idSize, j;
+      Byte longID[15];
+      RINOK(SzReadByte(sd, &mainByte));
+      idSize = (unsigned)(mainByte & 0xF);
+      RINOK(SzReadBytes(sd, longID, idSize));
+      if (idSize > sizeof(coder->MethodID))
+        return SZE_NOTIMPL;
+      coder->MethodID = 0;
+      for (j = 0; j < idSize; j++)
+        coder->MethodID |= (CMethodID)longID[idSize - 1 - j] << (8 * j);
+
+      if ((mainByte & 0x10) != 0)
+      {
+        RINOK(SzReadNumber32(sd, &coder->NumInStreams));
+        RINOK(SzReadNumber32(sd, &coder->NumOutStreams));
+      }
+      else
+      {
+        coder->NumInStreams = 1;
+        coder->NumOutStreams = 1;
+      }
+      if ((mainByte & 0x20) != 0)
+      {
+        UInt64 propertiesSize = 0;
+        RINOK(SzReadNumber(sd, &propertiesSize));
+        if (!SzByteBufferCreate(&coder->Properties, (size_t)propertiesSize, allocFunc))
+          return SZE_OUTOFMEMORY;
+        RINOK(SzReadBytes(sd, coder->Properties.Items, (size_t)propertiesSize));
+      }
+    }
+    while ((mainByte & 0x80) != 0)
+    {
+      RINOK(SzReadByte(sd, &mainByte));
+      RINOK(SzSkeepDataSize(sd, (mainByte & 0xF)));
+      if ((mainByte & 0x10) != 0)
+      {
+        UInt32 n;
+        RINOK(SzReadNumber32(sd, &n));
+        RINOK(SzReadNumber32(sd, &n));
+      }
+      if ((mainByte & 0x20) != 0)
+      {
+        UInt64 propertiesSize = 0;
+        RINOK(SzReadNumber(sd, &propertiesSize));
+        RINOK(SzSkeepDataSize(sd, propertiesSize));
+      }
+    }
+    numInStreams += (UInt32)coder->NumInStreams;
+    numOutStreams += (UInt32)coder->NumOutStreams;
+  }
+
+  numBindPairs = numOutStreams - 1;
+  folder->NumBindPairs = numBindPairs;
+
+
+  MY_ALLOC(CBindPair, folder->BindPairs, (size_t)numBindPairs, allocFunc);
+
+  for (i = 0; i < numBindPairs; i++)
+  {
+    CBindPair *bindPair = folder->BindPairs + i;;
+    RINOK(SzReadNumber32(sd, &bindPair->InIndex));
+    RINOK(SzReadNumber32(sd, &bindPair->OutIndex)); 
+  }
+
+  numPackedStreams = numInStreams - (UInt32)numBindPairs;
+
+  folder->NumPackStreams = numPackedStreams;
+  MY_ALLOC(UInt32, folder->PackStreams, (size_t)numPackedStreams, allocFunc);
+
+  if (numPackedStreams == 1)
+  {
+    UInt32 j;
+    UInt32 pi = 0;
+    for (j = 0; j < numInStreams; j++)
+      if (SzFolderFindBindPairForInStream(folder, j) < 0)
+      {
+        folder->PackStreams[pi++] = j;
+        break;
+      }
+  }
+  else
+    for(i = 0; i < numPackedStreams; i++)
+    {
+      RINOK(SzReadNumber32(sd, folder->PackStreams + i));
+    }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadUnPackInfo(
+    CSzData *sd, 
+    UInt32 *numFolders,
+    CFolder **folders,  /* for allocFunc */
+    void * (*allocFunc)(size_t size),
+    ISzAlloc *allocTemp)
+{
+  UInt32 i;
+  RINOK(SzWaitAttribute(sd, k7zIdFolder));
+  RINOK(SzReadNumber32(sd, numFolders));
+  {
+    RINOK(SzReadSwitch(sd));
+
+    MY_ALLOC(CFolder, *folders, (size_t)*numFolders, allocFunc);
+
+    for(i = 0; i < *numFolders; i++)
+      SzFolderInit((*folders) + i);
+
+    for(i = 0; i < *numFolders; i++)
+    {
+      RINOK(SzGetNextFolderItem(sd, (*folders) + i, allocFunc));
+    }
+  }
+
+  RINOK(SzWaitAttribute(sd, k7zIdCodersUnPackSize));
+
+  for(i = 0; i < *numFolders; i++)
+  {
+    UInt32 j;
+    CFolder *folder = (*folders) + i;
+    UInt32 numOutStreams = SzFolderGetNumOutStreams(folder);
+
+    MY_ALLOC(CFileSize, folder->UnPackSizes, (size_t)numOutStreams, allocFunc);
+
+    for(j = 0; j < numOutStreams; j++)
+    {
+      RINOK(SzReadSize(sd, folder->UnPackSizes + j));
+    }
+  }
+
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(SzReadID(sd, &type));
+    if (type == k7zIdEnd)
+      return SZ_OK;
+    if (type == k7zIdCRC)
+    {
+      SZ_RESULT res;
+      Byte *crcsDefined = 0;
+      UInt32 *crcs = 0;
+      res = SzReadHashDigests(sd, *numFolders, &crcsDefined, &crcs, allocTemp->Alloc); 
+      if (res == SZ_OK)
+      {
+        for(i = 0; i < *numFolders; i++)
+        {
+          CFolder *folder = (*folders) + i;
+          folder->UnPackCRCDefined = crcsDefined[i];
+          folder->UnPackCRC = crcs[i];
+        }
+      }
+      allocTemp->Free(crcs);
+      allocTemp->Free(crcsDefined);
+      RINOK(res);
+      continue;
+    }
+    RINOK(SzSkeepData(sd));
+  }
+}
+
+SZ_RESULT SzReadSubStreamsInfo(
+    CSzData *sd, 
+    UInt32 numFolders,
+    CFolder *folders,
+    UInt32 *numUnPackStreams,
+    CFileSize **unPackSizes,
+    Byte **digestsDefined,
+    UInt32 **digests,
+    ISzAlloc *allocTemp)
+{
+  UInt64 type = 0;
+  UInt32 i;
+  UInt32 si = 0;
+  UInt32 numDigests = 0;
+
+  for(i = 0; i < numFolders; i++)
+    folders[i].NumUnPackStreams = 1;
+  *numUnPackStreams = numFolders;
+
+  for (;;)
+  {
+    RINOK(SzReadID(sd, &type));
+    if (type == k7zIdNumUnPackStream)
+    {
+      *numUnPackStreams = 0;
+      for(i = 0; i < numFolders; i++)
+      {
+        UInt32 numStreams;
+        RINOK(SzReadNumber32(sd, &numStreams));
+        folders[i].NumUnPackStreams = numStreams;
+        *numUnPackStreams += numStreams;
+      }
+      continue;
+    }
+    if (type == k7zIdCRC || type == k7zIdSize)
+      break;
+    if (type == k7zIdEnd)
+      break;
+    RINOK(SzSkeepData(sd));
+  }
+
+  if (*numUnPackStreams == 0)
+  {
+    *unPackSizes = 0;
+    *digestsDefined = 0;
+    *digests = 0;
+  }
+  else
+  {
+    *unPackSizes = (CFileSize *)allocTemp->Alloc((size_t)*numUnPackStreams * sizeof(CFileSize));
+    RINOM(*unPackSizes);
+    *digestsDefined = (Byte *)allocTemp->Alloc((size_t)*numUnPackStreams * sizeof(Byte));
+    RINOM(*digestsDefined);
+    *digests = (UInt32 *)allocTemp->Alloc((size_t)*numUnPackStreams * sizeof(UInt32));
+    RINOM(*digests);
+  }
+
+  for(i = 0; i < numFolders; i++)
+  {
+    /*
+    v3.13 incorrectly worked with empty folders
+    v4.07: we check that folder is empty
+    */
+    CFileSize sum = 0;
+    UInt32 j;
+    UInt32 numSubstreams = folders[i].NumUnPackStreams;
+    if (numSubstreams == 0)
+      continue;
+    if (type == k7zIdSize)
+    for (j = 1; j < numSubstreams; j++)
+    {
+      CFileSize size;
+      RINOK(SzReadSize(sd, &size));
+      (*unPackSizes)[si++] = size;
+      sum += size;
+    }
+    (*unPackSizes)[si++] = SzFolderGetUnPackSize(folders + i) - sum;
+  }
+  if (type == k7zIdSize)
+  {
+    RINOK(SzReadID(sd, &type));
+  }
+
+  for(i = 0; i < *numUnPackStreams; i++)
+  {
+    (*digestsDefined)[i] = 0;
+    (*digests)[i] = 0;
+  }
+
+
+  for(i = 0; i < numFolders; i++)
+  {
+    UInt32 numSubstreams = folders[i].NumUnPackStreams;
+    if (numSubstreams != 1 || !folders[i].UnPackCRCDefined)
+      numDigests += numSubstreams;
+  }
+
+ 
+  si = 0;
+  for (;;)
+  {
+    if (type == k7zIdCRC)
+    {
+      int digestIndex = 0;
+      Byte *digestsDefined2 = 0; 
+      UInt32 *digests2 = 0;
+      SZ_RESULT res = SzReadHashDigests(sd, numDigests, &digestsDefined2, &digests2, allocTemp->Alloc);
+      if (res == SZ_OK)
+      {
+        for (i = 0; i < numFolders; i++)
+        {
+          CFolder *folder = folders + i;
+          UInt32 numSubstreams = folder->NumUnPackStreams;
+          if (numSubstreams == 1 && folder->UnPackCRCDefined)
+          {
+            (*digestsDefined)[si] = 1;
+            (*digests)[si] = folder->UnPackCRC;
+            si++;
+          }
+          else
+          {
+            UInt32 j;
+            for (j = 0; j < numSubstreams; j++, digestIndex++)
+            {
+              (*digestsDefined)[si] = digestsDefined2[digestIndex];
+              (*digests)[si] = digests2[digestIndex];
+              si++;
+            }
+          }
+        }
+      }
+      allocTemp->Free(digestsDefined2);
+      allocTemp->Free(digests2);
+      RINOK(res);
+    }
+    else if (type == k7zIdEnd)
+      return SZ_OK;
+    else
+    {
+      RINOK(SzSkeepData(sd));
+    }
+    RINOK(SzReadID(sd, &type));
+  }
+}
+
+
+SZ_RESULT SzReadStreamsInfo(
+    CSzData *sd, 
+    CFileSize *dataOffset,
+    CArchiveDatabase *db,
+    UInt32 *numUnPackStreams,
+    CFileSize **unPackSizes, /* allocTemp */
+    Byte **digestsDefined,   /* allocTemp */
+    UInt32 **digests,        /* allocTemp */
+    void * (*allocFunc)(size_t size),
+    ISzAlloc *allocTemp)
+{
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(SzReadID(sd, &type));
+    if ((UInt64)(int)type != type)
+      return SZE_FAIL;
+    switch((int)type)
+    {
+      case k7zIdEnd:
+        return SZ_OK;
+      case k7zIdPackInfo:
+      {
+        RINOK(SzReadPackInfo(sd, dataOffset, &db->NumPackStreams, 
+            &db->PackSizes, &db->PackCRCsDefined, &db->PackCRCs, allocFunc));
+        break;
+      }
+      case k7zIdUnPackInfo:
+      {
+        RINOK(SzReadUnPackInfo(sd, &db->NumFolders, &db->Folders, allocFunc, allocTemp));
+        break;
+      }
+      case k7zIdSubStreamsInfo:
+      {
+        RINOK(SzReadSubStreamsInfo(sd, db->NumFolders, db->Folders, 
+            numUnPackStreams, unPackSizes, digestsDefined, digests, allocTemp));
+        break;
+      }
+      default:
+        return SZE_FAIL;
+    }
+  }
+}
+
+Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+SZ_RESULT SzReadFileNames(CSzData *sd, UInt32 numFiles, CFileItem *files, 
+    void * (*allocFunc)(size_t size))
+{
+  UInt32 i;
+  for(i = 0; i < numFiles; i++)
+  {
+    UInt32 len = 0;
+    UInt32 pos = 0;
+    CFileItem *file = files + i;
+    while(pos + 2 <= sd->Size)
+    {
+      int numAdds;
+      UInt32 value = (UInt32)(sd->Data[pos] | (((UInt32)sd->Data[pos + 1]) << 8));
+      pos += 2;
+      len++;
+      if (value == 0)
+        break;
+      if (value < 0x80)
+        continue;
+      if (value >= 0xD800 && value < 0xE000)
+      {
+        UInt32 c2;
+        if (value >= 0xDC00)
+          return SZE_ARCHIVE_ERROR;
+        if (pos + 2 > sd->Size)
+          return SZE_ARCHIVE_ERROR;
+        c2 = (UInt32)(sd->Data[pos] | (((UInt32)sd->Data[pos + 1]) << 8));
+        pos += 2;
+        if (c2 < 0xDC00 || c2 >= 0xE000)
+          return SZE_ARCHIVE_ERROR;
+        value = ((value - 0xD800) << 10) | (c2 - 0xDC00);
+      }
+      for (numAdds = 1; numAdds < 5; numAdds++)
+        if (value < (((UInt32)1) << (numAdds * 5 + 6)))
+          break;
+      len += numAdds;
+    }
+
+    MY_ALLOC(char, file->Name, (size_t)len, allocFunc);
+
+    len = 0;
+    while(2 <= sd->Size)
+    {
+      int numAdds;
+      UInt32 value = (UInt32)(sd->Data[0] | (((UInt32)sd->Data[1]) << 8));
+      SzSkeepDataSize(sd, 2);
+      if (value < 0x80)
+      {
+        file->Name[len++] = (char)value;
+        if (value == 0)
+          break;
+        continue;
+      }
+      if (value >= 0xD800 && value < 0xE000)
+      {
+        UInt32 c2 = (UInt32)(sd->Data[0] | (((UInt32)sd->Data[1]) << 8));
+        SzSkeepDataSize(sd, 2);
+        value = ((value - 0xD800) << 10) | (c2 - 0xDC00);
+      }
+      for (numAdds = 1; numAdds < 5; numAdds++)
+        if (value < (((UInt32)1) << (numAdds * 5 + 6)))
+          break;
+      file->Name[len++] = (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds)));
+      do
+      {
+        numAdds--;
+        file->Name[len++] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F));
+      }
+      while(numAdds > 0);
+
+      len += numAdds;
+    }
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadHeader2(
+    CSzData *sd, 
+    CArchiveDatabaseEx *db,   /* allocMain */
+    CFileSize **unPackSizes,  /* allocTemp */
+    Byte **digestsDefined,    /* allocTemp */
+    UInt32 **digests,         /* allocTemp */
+    Byte **emptyStreamVector, /* allocTemp */
+    Byte **emptyFileVector,   /* allocTemp */
+    Byte **lwtVector,         /* allocTemp */
+    ISzAlloc *allocMain, 
+    ISzAlloc *allocTemp)
+{
+  UInt64 type;
+  UInt32 numUnPackStreams = 0;
+  UInt32 numFiles = 0;
+  CFileItem *files = 0;
+  UInt32 numEmptyStreams = 0;
+  UInt32 i;
+
+  RINOK(SzReadID(sd, &type));
+
+  if (type == k7zIdArchiveProperties)
+  {
+    RINOK(SzReadArchiveProperties(sd));
+    RINOK(SzReadID(sd, &type));
+  }
+ 
+ 
+  if (type == k7zIdMainStreamsInfo)
+  {
+    RINOK(SzReadStreamsInfo(sd,
+        &db->ArchiveInfo.DataStartPosition,
+        &db->Database, 
+        &numUnPackStreams,
+        unPackSizes,
+        digestsDefined,
+        digests, allocMain->Alloc, allocTemp));
+    db->ArchiveInfo.DataStartPosition += db->ArchiveInfo.StartPositionAfterHeader;
+    RINOK(SzReadID(sd, &type));
+  }
+
+  if (type == k7zIdEnd)
+    return SZ_OK;
+  if (type != k7zIdFilesInfo)
+    return SZE_ARCHIVE_ERROR;
+  
+  RINOK(SzReadNumber32(sd, &numFiles));
+  db->Database.NumFiles = numFiles;
+
+  MY_ALLOC(CFileItem, files, (size_t)numFiles, allocMain->Alloc);
+
+  db->Database.Files = files;
+  for(i = 0; i < numFiles; i++)
+    SzFileInit(files + i);
+
+  for (;;)
+  {
+    UInt64 type;
+    UInt64 size;
+    RINOK(SzReadID(sd, &type));
+    if (type == k7zIdEnd)
+      break;
+    RINOK(SzReadNumber(sd, &size));
+
+    if ((UInt64)(int)type != type)
+    {
+      RINOK(SzSkeepDataSize(sd, size));
+    }
+    else
+    switch((int)type)
+    {
+      case k7zIdName:
+      {
+        RINOK(SzReadSwitch(sd));
+        RINOK(SzReadFileNames(sd, numFiles, files, allocMain->Alloc))
+        break;
+      }
+      case k7zIdEmptyStream:
+      {
+        RINOK(SzReadBoolVector(sd, numFiles, emptyStreamVector, allocTemp->Alloc));
+        numEmptyStreams = 0;
+        for (i = 0; i < numFiles; i++)
+          if ((*emptyStreamVector)[i])
+            numEmptyStreams++;
+        break;
+      }
+      case k7zIdEmptyFile:
+      {
+        RINOK(SzReadBoolVector(sd, numEmptyStreams, emptyFileVector, allocTemp->Alloc));
+        break;
+      }
+      case k7zIdLastWriteTime:
+      {
+        RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp->Alloc));
+        RINOK(SzReadSwitch(sd));
+        for (i = 0; i < numFiles; i++)
+        {
+          CFileItem *f = &files[i];
+          Byte defined = (*lwtVector)[i];
+          f->IsLastWriteTimeDefined = defined;
+          f->LastWriteTime.Low = f->LastWriteTime.High = 0;
+          if (defined)
+          {
+            RINOK(SzReadUInt32(sd, &f->LastWriteTime.Low));
+            RINOK(SzReadUInt32(sd, &f->LastWriteTime.High));
+          }
+        }
+        break;
+      }
+      default:
+      {
+        RINOK(SzSkeepDataSize(sd, size));
+      }
+    }
+  }
+
+  {
+    UInt32 emptyFileIndex = 0;
+    UInt32 sizeIndex = 0;
+    for(i = 0; i < numFiles; i++)
+    {
+      CFileItem *file = files + i;
+      file->IsAnti = 0;
+      if (*emptyStreamVector == 0)
+        file->HasStream = 1;
+      else
+        file->HasStream = (Byte)((*emptyStreamVector)[i] ? 0 : 1);
+      if(file->HasStream)
+      {
+        file->IsDirectory = 0;
+        file->Size = (*unPackSizes)[sizeIndex];
+        file->FileCRC = (*digests)[sizeIndex];
+        file->IsFileCRCDefined = (Byte)(*digestsDefined)[sizeIndex];
+        sizeIndex++;
+      }
+      else
+      {
+        if (*emptyFileVector == 0)
+          file->IsDirectory = 1;
+        else
+          file->IsDirectory = (Byte)((*emptyFileVector)[emptyFileIndex] ? 0 : 1);
+        emptyFileIndex++;
+        file->Size = 0;
+        file->IsFileCRCDefined = 0;
+      }
+    }
+  }
+  return SzArDbExFill(db, allocMain->Alloc);
+}
+
+SZ_RESULT SzReadHeader(
+    CSzData *sd, 
+    CArchiveDatabaseEx *db, 
+    ISzAlloc *allocMain, 
+    ISzAlloc *allocTemp)
+{
+  CFileSize *unPackSizes = 0;
+  Byte *digestsDefined = 0;
+  UInt32 *digests = 0;
+  Byte *emptyStreamVector = 0;
+  Byte *emptyFileVector = 0;
+  Byte *lwtVector = 0;
+  SZ_RESULT res = SzReadHeader2(sd, db, 
+      &unPackSizes, &digestsDefined, &digests,
+      &emptyStreamVector, &emptyFileVector, &lwtVector, 
+      allocMain, allocTemp);
+  allocTemp->Free(unPackSizes);
+  allocTemp->Free(digestsDefined);
+  allocTemp->Free(digests);
+  allocTemp->Free(emptyStreamVector);
+  allocTemp->Free(emptyFileVector);
+  allocTemp->Free(lwtVector);
+  return res;
+} 
+
+SZ_RESULT SzReadAndDecodePackedStreams2(
+    ISzInStream *inStream, 
+    CSzData *sd,
+    CSzByteBuffer *outBuffer,
+    CFileSize baseOffset, 
+    CArchiveDatabase *db,
+    CFileSize **unPackSizes,
+    Byte **digestsDefined,
+    UInt32 **digests,
+    #ifndef _LZMA_IN_CB
+    Byte **inBuffer,
+    #endif
+    ISzAlloc *allocTemp)
+{
+
+  UInt32 numUnPackStreams = 0;
+  CFileSize dataStartPos;
+  CFolder *folder;
+  #ifndef _LZMA_IN_CB
+  CFileSize packSize = 0;
+  UInt32 i = 0;
+  #endif
+  CFileSize unPackSize;
+  SZ_RESULT res;
+
+  RINOK(SzReadStreamsInfo(sd, &dataStartPos, db,
+      &numUnPackStreams,  unPackSizes, digestsDefined, digests, 
+      allocTemp->Alloc, allocTemp));
+  
+  dataStartPos += baseOffset;
+  if (db->NumFolders != 1)
+    return SZE_ARCHIVE_ERROR;
+
+  folder = db->Folders;
+  unPackSize = SzFolderGetUnPackSize(folder);
+  
+  RINOK(inStream->Seek(inStream, dataStartPos));
+
+  #ifndef _LZMA_IN_CB
+  for (i = 0; i < db->NumPackStreams; i++)
+    packSize += db->PackSizes[i];
+
+  MY_ALLOC(Byte, *inBuffer, (size_t)packSize, allocTemp->Alloc);
+
+  RINOK(SafeReadDirect(inStream, *inBuffer, (size_t)packSize));
+  #endif
+
+  if (!SzByteBufferCreate(outBuffer, (size_t)unPackSize, allocTemp->Alloc))
+    return SZE_OUTOFMEMORY;
+  
+  res = SzDecode(db->PackSizes, folder, 
+          #ifdef _LZMA_IN_CB
+          inStream, dataStartPos, 
+          #else
+          *inBuffer, 
+          #endif
+          outBuffer->Items, (size_t)unPackSize, allocTemp);
+  RINOK(res)
+  if (folder->UnPackCRCDefined)
+    if (CrcCalc(outBuffer->Items, (size_t)unPackSize) != folder->UnPackCRC)
+      return SZE_FAIL;
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadAndDecodePackedStreams(
+    ISzInStream *inStream, 
+    CSzData *sd,
+    CSzByteBuffer *outBuffer,
+    CFileSize baseOffset, 
+    ISzAlloc *allocTemp)
+{
+  CArchiveDatabase db;
+  CFileSize *unPackSizes = 0;
+  Byte *digestsDefined = 0;
+  UInt32 *digests = 0;
+  #ifndef _LZMA_IN_CB
+  Byte *inBuffer = 0;
+  #endif
+  SZ_RESULT res;
+  SzArchiveDatabaseInit(&db);
+  res = SzReadAndDecodePackedStreams2(inStream, sd, outBuffer, baseOffset, 
+    &db, &unPackSizes, &digestsDefined, &digests, 
+    #ifndef _LZMA_IN_CB
+    &inBuffer,
+    #endif
+    allocTemp);
+  SzArchiveDatabaseFree(&db, allocTemp->Free);
+  allocTemp->Free(unPackSizes);
+  allocTemp->Free(digestsDefined);
+  allocTemp->Free(digests);
+  #ifndef _LZMA_IN_CB
+  allocTemp->Free(inBuffer);
+  #endif
+  return res;
+}
+
+SZ_RESULT SzArchiveOpen2(
+    ISzInStream *inStream, 
+    CArchiveDatabaseEx *db,
+    ISzAlloc *allocMain, 
+    ISzAlloc *allocTemp)
+{
+  Byte signature[k7zSignatureSize];
+  Byte version;
+  UInt32 crcFromArchive;
+  UInt64 nextHeaderOffset;
+  UInt64 nextHeaderSize;
+  UInt32 nextHeaderCRC;
+  UInt32 crc = 0;
+  CFileSize pos = 0;
+  CSzByteBuffer buffer;
+  CSzData sd;
+  SZ_RESULT res;
+
+  RINOK(SafeReadDirect(inStream, signature, k7zSignatureSize));
+
+  if (!TestSignatureCandidate(signature))
+    return SZE_ARCHIVE_ERROR;
+
+  /*
+  db.Clear();
+  db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;
+  */
+  RINOK(SafeReadDirectByte(inStream, &version));
+  if (version != k7zMajorVersion)
+    return SZE_ARCHIVE_ERROR;
+  RINOK(SafeReadDirectByte(inStream, &version));
+
+  RINOK(SafeReadDirectUInt32(inStream, &crcFromArchive, &crc));
+
+  crc = CRC_INIT_VAL;
+  RINOK(SafeReadDirectUInt64(inStream, &nextHeaderOffset, &crc));
+  RINOK(SafeReadDirectUInt64(inStream, &nextHeaderSize, &crc));
+  RINOK(SafeReadDirectUInt32(inStream, &nextHeaderCRC, &crc));
+
+  pos = k7zStartHeaderSize;
+  db->ArchiveInfo.StartPositionAfterHeader = pos;
+  
+  if (CRC_GET_DIGEST(crc) != crcFromArchive)
+    return SZE_ARCHIVE_ERROR;
+
+  if (nextHeaderSize == 0)
+    return SZ_OK;
+
+  RINOK(inStream->Seek(inStream, (CFileSize)(pos + nextHeaderOffset)));
+
+  if (!SzByteBufferCreate(&buffer, (size_t)nextHeaderSize, allocTemp->Alloc))
+    return SZE_OUTOFMEMORY;
+
+  res = SafeReadDirect(inStream, buffer.Items, (size_t)nextHeaderSize);
+  if (res == SZ_OK)
+  {
+    res = SZE_ARCHIVE_ERROR;
+    if (CrcCalc(buffer.Items, (UInt32)nextHeaderSize) == nextHeaderCRC)
+    {
+      for (;;)
+      {
+        UInt64 type;
+        sd.Data = buffer.Items;
+        sd.Size = buffer.Capacity;
+        res = SzReadID(&sd, &type);
+        if (res != SZ_OK)
+          break;
+        if (type == k7zIdHeader)
+        {
+          res = SzReadHeader(&sd, db, allocMain, allocTemp);
+          break;
+        }
+        if (type != k7zIdEncodedHeader)
+        {
+          res = SZE_ARCHIVE_ERROR;
+          break;
+        }
+        {
+          CSzByteBuffer outBuffer;
+          res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer, 
+              db->ArchiveInfo.StartPositionAfterHeader, 
+              allocTemp);
+          if (res != SZ_OK)
+          {
+            SzByteBufferFree(&outBuffer, allocTemp->Free);
+            break;
+          }
+          SzByteBufferFree(&buffer, allocTemp->Free);
+          buffer.Items = outBuffer.Items;
+          buffer.Capacity = outBuffer.Capacity;
+        }
+      }
+    }
+  }
+  SzByteBufferFree(&buffer, allocTemp->Free);
+  return res;
+}
+
+SZ_RESULT SzArchiveOpen(
+    ISzInStream *inStream, 
+    CArchiveDatabaseEx *db,
+    ISzAlloc *allocMain, 
+    ISzAlloc *allocTemp)
+{
+  SZ_RESULT res = SzArchiveOpen2(inStream, db, allocMain, allocTemp);
+  if (res != SZ_OK)
+    SzArDbExFree(db, allocMain->Free);
+  return res;
+}

+ 55 - 0
lzma/C/Archive/7z/7zIn.h

@@ -0,0 +1,55 @@
+/* 7zIn.h */
+
+#ifndef __7Z_IN_H
+#define __7Z_IN_H
+
+#include "7zHeader.h"
+#include "7zItem.h"
+#include "7zAlloc.h"
+ 
+typedef struct _CInArchiveInfo
+{
+  CFileSize StartPositionAfterHeader; 
+  CFileSize DataStartPosition;
+}CInArchiveInfo;
+
+typedef struct _CArchiveDatabaseEx
+{
+  CArchiveDatabase Database;
+  CInArchiveInfo ArchiveInfo;
+  UInt32 *FolderStartPackStreamIndex;
+  CFileSize *PackStreamStartPositions;
+  UInt32 *FolderStartFileIndex;
+  UInt32 *FileIndexToFolderIndexMap;
+}CArchiveDatabaseEx;
+
+void SzArDbExInit(CArchiveDatabaseEx *db);
+void SzArDbExFree(CArchiveDatabaseEx *db, void (*freeFunc)(void *));
+CFileSize SzArDbGetFolderStreamPos(CArchiveDatabaseEx *db, UInt32 folderIndex, UInt32 indexInFolder);
+int SzArDbGetFolderFullPackSize(CArchiveDatabaseEx *db, UInt32 folderIndex, CFileSize *resSize);
+
+typedef struct _ISzInStream
+{
+  #ifdef _LZMA_IN_CB
+  SZ_RESULT (*Read)(
+      void *object,           /* pointer to ISzInStream itself */
+      void **buffer,          /* out: pointer to buffer with data */
+      size_t maxRequiredSize, /* max required size to read */
+      size_t *processedSize); /* real processed size. 
+                                 processedSize can be less than maxRequiredSize.
+                                 If processedSize == 0, then there are no more 
+                                 bytes in stream. */
+  #else
+  SZ_RESULT (*Read)(void *object, void *buffer, size_t size, size_t *processedSize);
+  #endif
+  SZ_RESULT (*Seek)(void *object, CFileSize pos);
+} ISzInStream;
+
+ 
+int SzArchiveOpen(
+    ISzInStream *inStream, 
+    CArchiveDatabaseEx *db,
+    ISzAlloc *allocMain, 
+    ISzAlloc *allocTemp);
+ 
+#endif

+ 134 - 0
lzma/C/Archive/7z/7zItem.c

@@ -0,0 +1,134 @@
+/* 7zItem.c */
+
+#include "7zItem.h"
+#include "7zAlloc.h"
+
+void SzCoderInfoInit(CCoderInfo *coder)
+{
+  SzByteBufferInit(&coder->Properties);
+}
+
+void SzCoderInfoFree(CCoderInfo *coder, void (*freeFunc)(void *p))
+{
+  SzByteBufferFree(&coder->Properties, freeFunc);
+  SzCoderInfoInit(coder);
+}
+
+void SzFolderInit(CFolder *folder)
+{
+  folder->NumCoders = 0;
+  folder->Coders = 0;
+  folder->NumBindPairs = 0;
+  folder->BindPairs = 0;
+  folder->NumPackStreams = 0;
+  folder->PackStreams = 0;
+  folder->UnPackSizes = 0;
+  folder->UnPackCRCDefined = 0;
+  folder->UnPackCRC = 0;
+  folder->NumUnPackStreams = 0;
+}
+
+void SzFolderFree(CFolder *folder, void (*freeFunc)(void *p))
+{
+  UInt32 i;
+  for (i = 0; i < folder->NumCoders; i++)
+    SzCoderInfoFree(&folder->Coders[i], freeFunc);
+  freeFunc(folder->Coders);
+  freeFunc(folder->BindPairs);
+  freeFunc(folder->PackStreams);
+  freeFunc(folder->UnPackSizes);
+  SzFolderInit(folder);
+}
+
+UInt32 SzFolderGetNumOutStreams(CFolder *folder)
+{
+  UInt32 result = 0;
+  UInt32 i;
+  for (i = 0; i < folder->NumCoders; i++)
+    result += folder->Coders[i].NumOutStreams;
+  return result;
+}
+
+int SzFolderFindBindPairForInStream(CFolder *folder, UInt32 inStreamIndex)
+{
+  UInt32 i;
+  for(i = 0; i < folder->NumBindPairs; i++)
+    if (folder->BindPairs[i].InIndex == inStreamIndex)
+      return i;
+  return -1;
+}
+
+
+int SzFolderFindBindPairForOutStream(CFolder *folder, UInt32 outStreamIndex)
+{
+  UInt32 i;
+  for(i = 0; i < folder->NumBindPairs; i++)
+    if (folder->BindPairs[i].OutIndex == outStreamIndex)
+      return i;
+  return -1;
+}
+
+CFileSize SzFolderGetUnPackSize(CFolder *folder)
+{ 
+  int i = (int)SzFolderGetNumOutStreams(folder);
+  if (i == 0)
+    return 0;
+  for (i--; i >= 0; i--)
+    if (SzFolderFindBindPairForOutStream(folder, i) < 0)
+      return folder->UnPackSizes[i];
+  /* throw 1; */
+  return 0;
+}
+
+/*
+int FindPackStreamArrayIndex(int inStreamIndex) const
+{
+  for(int i = 0; i < PackStreams.Size(); i++)
+  if (PackStreams[i] == inStreamIndex)
+    return i;
+  return -1;
+}
+*/
+
+void SzFileInit(CFileItem *fileItem)
+{
+  fileItem->IsFileCRCDefined = 0;
+  fileItem->HasStream = 1;
+  fileItem->IsDirectory = 0;
+  fileItem->IsAnti = 0;
+  fileItem->IsLastWriteTimeDefined = 0;
+  fileItem->Name = 0;
+}
+
+void SzFileFree(CFileItem *fileItem, void (*freeFunc)(void *p))
+{
+  freeFunc(fileItem->Name);
+  SzFileInit(fileItem);
+}
+
+void SzArchiveDatabaseInit(CArchiveDatabase *db)
+{
+  db->NumPackStreams = 0;
+  db->PackSizes = 0;
+  db->PackCRCsDefined = 0;
+  db->PackCRCs = 0;
+  db->NumFolders = 0;
+  db->Folders = 0;
+  db->NumFiles = 0;
+  db->Files = 0;
+}
+
+void SzArchiveDatabaseFree(CArchiveDatabase *db, void (*freeFunc)(void *))
+{
+  UInt32 i;
+  for (i = 0; i < db->NumFolders; i++)
+    SzFolderFree(&db->Folders[i], freeFunc);
+  for (i = 0; i < db->NumFiles; i++)
+    SzFileFree(&db->Files[i], freeFunc);
+  freeFunc(db->PackSizes);
+  freeFunc(db->PackCRCsDefined);
+  freeFunc(db->PackCRCs);
+  freeFunc(db->Folders);
+  freeFunc(db->Files);
+  SzArchiveDatabaseInit(db);
+}

+ 95 - 0
lzma/C/Archive/7z/7zItem.h

@@ -0,0 +1,95 @@
+/* 7zItem.h */
+
+#ifndef __7Z_ITEM_H
+#define __7Z_ITEM_H
+
+#include "7zMethodID.h"
+#include "7zHeader.h"
+#include "7zBuffer.h"
+
+typedef struct _CCoderInfo
+{
+  UInt32 NumInStreams;
+  UInt32 NumOutStreams;
+  CMethodID MethodID;
+  CSzByteBuffer Properties;
+}CCoderInfo;
+
+void SzCoderInfoInit(CCoderInfo *coder);
+void SzCoderInfoFree(CCoderInfo *coder, void (*freeFunc)(void *p));
+
+typedef struct _CBindPair
+{
+  UInt32 InIndex;
+  UInt32 OutIndex;
+}CBindPair;
+
+typedef struct _CFolder
+{
+  UInt32 NumCoders;
+  CCoderInfo *Coders;
+  UInt32 NumBindPairs;
+  CBindPair *BindPairs;
+  UInt32 NumPackStreams; 
+  UInt32 *PackStreams;
+  CFileSize *UnPackSizes;
+  int UnPackCRCDefined;
+  UInt32 UnPackCRC;
+
+  UInt32 NumUnPackStreams;
+}CFolder;
+
+void SzFolderInit(CFolder *folder);
+CFileSize SzFolderGetUnPackSize(CFolder *folder);
+int SzFolderFindBindPairForInStream(CFolder *folder, UInt32 inStreamIndex);
+UInt32 SzFolderGetNumOutStreams(CFolder *folder);
+CFileSize SzFolderGetUnPackSize(CFolder *folder);
+
+typedef struct _CArchiveFileTime
+{
+  UInt32 Low;
+  UInt32 High;
+} CArchiveFileTime;
+
+typedef struct _CFileItem
+{
+  CArchiveFileTime LastWriteTime;
+  /*
+  CFileSize StartPos;
+  UInt32 Attributes; 
+  */
+  CFileSize Size;
+  UInt32 FileCRC;
+  char *Name;
+
+  Byte IsFileCRCDefined;
+  Byte HasStream;
+  Byte IsDirectory;
+  Byte IsAnti;
+  Byte IsLastWriteTimeDefined;
+  /*
+  int AreAttributesDefined;
+  int IsLastWriteTimeDefined;
+  int IsStartPosDefined;
+  */
+}CFileItem;
+
+void SzFileInit(CFileItem *fileItem);
+
+typedef struct _CArchiveDatabase
+{
+  UInt32 NumPackStreams;
+  CFileSize *PackSizes;
+  Byte *PackCRCsDefined;
+  UInt32 *PackCRCs;
+  UInt32 NumFolders;
+  CFolder *Folders;
+  UInt32 NumFiles;
+  CFileItem *Files;
+}CArchiveDatabase;
+
+void SzArchiveDatabaseInit(CArchiveDatabase *db);
+void SzArchiveDatabaseFree(CArchiveDatabase *db, void (*freeFunc)(void *));
+
+
+#endif

+ 428 - 0
lzma/C/Archive/7z/7zMain.c

@@ -0,0 +1,428 @@
+/* 
+7zMain.c
+Test application for 7z Decoder
+LZMA SDK 4.43 Copyright (c) 1999-2006 Igor Pavlov (2006-06-04)
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _WIN32
+#define USE_WINDOWS_FUNCTIONS
+#endif
+
+#ifdef USE_WINDOWS_FUNCTIONS
+#include <windows.h>
+#endif
+
+#include "7zIn.h"
+#include "7zExtract.h"
+
+#include "../../7zCrc.h"
+
+
+#ifdef USE_WINDOWS_FUNCTIONS
+typedef HANDLE MY_FILE_HANDLE;
+#else
+typedef FILE *MY_FILE_HANDLE;
+#endif
+
+void ConvertNumberToString(CFileSize value, char *s)
+{
+  char temp[32];
+  int pos = 0;
+  do 
+  {
+    temp[pos++] = (char)('0' + (int)(value % 10));
+    value /= 10;
+  }
+  while (value != 0);
+  do
+    *s++ = temp[--pos];
+  while(pos > 0);
+  *s = '\0';
+}
+
+#define PERIOD_4 (4 * 365 + 1)
+#define PERIOD_100 (PERIOD_4 * 25 - 1)
+#define PERIOD_400 (PERIOD_100 * 4 + 1)
+
+void ConvertFileTimeToString(CArchiveFileTime *ft, char *s)
+{
+  unsigned year, mon, day, hour, min, sec;
+  UInt64 v64 = ft->Low | ((UInt64)ft->High << 32);
+  Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+  unsigned temp;
+  UInt32 v; 
+  v64 /= 10000000;
+  sec = (unsigned)(v64 % 60);
+  v64 /= 60;
+  min = (unsigned)(v64 % 60);
+  v64 /= 60;
+  hour = (unsigned)(v64 % 24);
+  v64 /= 24;
+
+  v = (UInt32)v64;
+
+  year = (unsigned)(1601 + v / PERIOD_400 * 400);
+  v %= PERIOD_400;
+
+  temp = (unsigned)(v / PERIOD_100);
+  if (temp == 4)
+    temp = 3;
+  year += temp * 100;
+  v -= temp * PERIOD_100;
+
+  temp = v / PERIOD_4;
+  if (temp == 25)
+    temp = 24;
+  year += temp * 4;
+  v -= temp * PERIOD_4;
+
+  temp = v / 365;
+  if (temp == 4)
+    temp = 3;
+  year += temp;
+  v -= temp * 365;
+
+  if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
+    ms[1] = 29;
+  for (mon = 1; mon <= 12; mon++)
+  {
+    unsigned s = ms[mon - 1];
+    if (v < s)
+      break;
+    v -= s;
+  }
+  day = (unsigned)v + 1;
+  sprintf(s, "%04d-%02d-%02d %02d:%02d:%02d", year, mon, day, hour, min, sec);
+}
+
+
+#ifdef USE_WINDOWS_FUNCTIONS
+/*
+   ReadFile and WriteFile functions in Windows have BUG:
+   If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) 
+   from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES 
+   (Insufficient system resources exist to complete the requested service).
+*/
+#define kChunkSizeMax (1 << 24)
+#endif
+
+size_t MyReadFile(MY_FILE_HANDLE file, void *data, size_t size)
+{ 
+  if (size == 0)
+    return 0;
+  #ifdef USE_WINDOWS_FUNCTIONS
+  {
+    size_t processedSize = 0;
+    do
+    {
+      DWORD curSize = (size > kChunkSizeMax) ? kChunkSizeMax : (DWORD)size;
+      DWORD processedLoc = 0;
+      BOOL res = ReadFile(file, data, curSize, &processedLoc, NULL);
+      data = (void *)((unsigned char *)data + processedLoc);
+      size -= processedLoc;
+      processedSize += processedLoc;
+      if (!res || processedLoc == 0)
+        break;
+    }
+    while (size > 0);
+    return processedSize;
+  }
+  #else
+  return fread(data, 1, size, file); 
+  #endif
+}
+
+size_t MyWriteFile(MY_FILE_HANDLE file, void *data, size_t size)
+{ 
+  if (size == 0)
+    return 0;
+  #ifdef USE_WINDOWS_FUNCTIONS
+  {
+    size_t processedSize = 0;
+    do
+    {
+      DWORD curSize = (size > kChunkSizeMax) ? kChunkSizeMax : (DWORD)size;
+      DWORD processedLoc = 0;
+      BOOL res = WriteFile(file, data, curSize, &processedLoc, NULL);
+      data = (void *)((unsigned char *)data + processedLoc);
+      size -= processedLoc;
+      processedSize += processedLoc;
+      if (!res)
+        break;
+    }
+    while (size > 0);
+    return processedSize;
+  }
+  #else
+  return fwrite(data, 1, size, file); 
+  #endif
+}
+
+int MyCloseFile(MY_FILE_HANDLE file)
+{ 
+  #ifdef USE_WINDOWS_FUNCTIONS
+  return (CloseHandle(file) != FALSE) ? 0 : 1;
+  #else
+  return fclose(file); 
+  #endif
+}
+
+typedef struct _CFileInStream
+{
+  ISzInStream InStream;
+  MY_FILE_HANDLE File;
+} CFileInStream;
+
+#ifdef _LZMA_IN_CB
+
+#define kBufferSize (1 << 12)
+Byte g_Buffer[kBufferSize];
+
+SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxRequiredSize, size_t *processedSize)
+{
+  CFileInStream *s = (CFileInStream *)object;
+  size_t processedSizeLoc;
+  if (maxRequiredSize > kBufferSize)
+    maxRequiredSize = kBufferSize;
+  processedSizeLoc = MyReadFile(s->File, g_Buffer, maxRequiredSize);
+  *buffer = g_Buffer;
+  if (processedSize != 0)
+    *processedSize = processedSizeLoc;
+  return SZ_OK;
+}
+
+#else
+
+SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size, size_t *processedSize)
+{
+  CFileInStream *s = (CFileInStream *)object;
+  size_t processedSizeLoc = MyReadFile(s->File, buffer, size);
+  if (processedSize != 0)
+    *processedSize = processedSizeLoc;
+  return SZ_OK;
+}
+
+#endif
+
+SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
+{
+  CFileInStream *s = (CFileInStream *)object;
+
+  #ifdef USE_WINDOWS_FUNCTIONS
+  {
+    LARGE_INTEGER value;
+    value.LowPart = (DWORD)pos;
+    value.HighPart = (LONG)((UInt64)pos >> 32);
+    #ifdef _SZ_FILE_SIZE_32
+    /* VC 6.0 has bug with >> 32 shifts. */
+    value.HighPart = 0;
+    #endif
+    value.LowPart = SetFilePointer(s->File, value.LowPart, &value.HighPart, FILE_BEGIN);
+    if (value.LowPart == 0xFFFFFFFF)
+      if(GetLastError() != NO_ERROR) 
+        return SZE_FAIL;
+    return SZ_OK;
+  }
+  #else
+  int res = fseek(s->File, (long)pos, SEEK_SET);
+  if (res == 0)
+    return SZ_OK;
+  return SZE_FAIL;
+  #endif
+}
+
+void PrintError(char *sz)
+{
+  printf("\nERROR: %s\n", sz);
+}
+
+int main(int numargs, char *args[])
+{
+  CFileInStream archiveStream;
+  CArchiveDatabaseEx db;
+  SZ_RESULT res;
+  ISzAlloc allocImp;
+  ISzAlloc allocTempImp;
+
+  printf("\n7z ANSI-C Decoder 4.48  Copyright (c) 1999-2007 Igor Pavlov  2007-06-21\n");
+  if (numargs == 1)
+  {
+    printf(
+      "\nUsage: 7zDec <command> <archive_name>\n\n"
+      "<Commands>\n"
+      "  e: Extract files from archive\n"
+      "  l: List contents of archive\n"
+      "  t: Test integrity of archive\n");
+    return 0;
+  }
+  if (numargs < 3)
+  {
+    PrintError("incorrect command");
+    return 1;
+  }
+
+  archiveStream.File = 
+  #ifdef USE_WINDOWS_FUNCTIONS
+  CreateFile(args[2], GENERIC_READ, FILE_SHARE_READ, 
+      NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+  if (archiveStream.File == INVALID_HANDLE_VALUE)
+  #else
+  archiveStream.File = fopen(args[2], "rb");
+  if (archiveStream.File == 0)
+  #endif
+  {
+    PrintError("can not open input file");
+    return 1;
+  }
+
+  archiveStream.InStream.Read = SzFileReadImp;
+  archiveStream.InStream.Seek = SzFileSeekImp;
+
+  allocImp.Alloc = SzAlloc;
+  allocImp.Free = SzFree;
+
+  allocTempImp.Alloc = SzAllocTemp;
+  allocTempImp.Free = SzFreeTemp;
+
+  CrcGenerateTable();
+
+  SzArDbExInit(&db);
+  res = SzArchiveOpen(&archiveStream.InStream, &db, &allocImp, &allocTempImp);
+  if (res == SZ_OK)
+  {
+    char *command = args[1];
+    int listCommand = 0;
+    int testCommand = 0;
+    int extractCommand = 0;
+    if (strcmp(command, "l") == 0)
+      listCommand = 1;
+    if (strcmp(command, "t") == 0)
+      testCommand = 1;
+    else if (strcmp(command, "e") == 0)
+      extractCommand = 1;
+
+    if (listCommand)
+    {
+      UInt32 i;
+      for (i = 0; i < db.Database.NumFiles; i++)
+      {
+        CFileItem *f = db.Database.Files + i;
+        char s[32], t[32];
+        ConvertNumberToString(f->Size, s);
+        if (f->IsLastWriteTimeDefined)
+          ConvertFileTimeToString(&f->LastWriteTime, t);
+        else
+          strcpy(t, "                   ");
+
+        printf("%10s %s  %s\n", s, t, f->Name);
+      }
+    }
+    else if (testCommand || extractCommand)
+    {
+      UInt32 i;
+
+      /*
+      if you need cache, use these 3 variables.
+      if you use external function, you can make these variable as static.
+      */
+      UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */
+      Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */
+      size_t outBufferSize = 0;  /* it can have any value before first call (if outBuffer = 0) */
+
+      printf("\n");
+      for (i = 0; i < db.Database.NumFiles; i++)
+      {
+        size_t offset;
+        size_t outSizeProcessed;
+        CFileItem *f = db.Database.Files + i;
+        if (f->IsDirectory)
+          printf("Directory ");
+        else
+          printf(testCommand ? 
+            "Testing   ":
+            "Extracting");
+        printf(" %s", f->Name);
+        if (f->IsDirectory)
+        {
+          printf("\n");
+          continue;
+        }
+        res = SzExtract(&archiveStream.InStream, &db, i, 
+            &blockIndex, &outBuffer, &outBufferSize, 
+            &offset, &outSizeProcessed, 
+            &allocImp, &allocTempImp);
+        if (res != SZ_OK)
+          break;
+        if (!testCommand)
+        {
+          MY_FILE_HANDLE outputHandle;
+          size_t processedSize;
+          char *fileName = f->Name;
+          size_t nameLen = strlen(f->Name);
+          for (; nameLen > 0; nameLen--)
+            if (f->Name[nameLen - 1] == '/')
+            {
+              fileName = f->Name + nameLen;
+              break;
+            }
+            
+          outputHandle = 
+          #ifdef USE_WINDOWS_FUNCTIONS
+            CreateFile(fileName, GENERIC_WRITE, FILE_SHARE_READ, 
+                NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+          if (outputHandle == INVALID_HANDLE_VALUE)
+          #else
+          fopen(fileName, "wb+");
+          if (outputHandle == 0)
+          #endif
+          {
+            PrintError("can not open output file");
+            res = SZE_FAIL;
+            break;
+          }
+          processedSize = MyWriteFile(outputHandle, outBuffer + offset, outSizeProcessed);
+          if (processedSize != outSizeProcessed)
+          {
+            PrintError("can not write output file");
+            res = SZE_FAIL;
+            break;
+          }
+          if (MyCloseFile(outputHandle))
+          {
+            PrintError("can not close output file");
+            res = SZE_FAIL;
+            break;
+          }
+        }
+        printf("\n");
+      }
+      allocImp.Free(outBuffer);
+    }
+    else
+    {
+      PrintError("incorrect command");
+      res = SZE_FAIL;
+    }
+  }
+  SzArDbExFree(&db, allocImp.Free);
+
+  MyCloseFile(archiveStream.File);
+  if (res == SZ_OK)
+  {
+    printf("\nEverything is Ok\n");
+    return 0;
+  }
+  if (res == (SZ_RESULT)SZE_NOTIMPL)
+    PrintError("decoder doesn't support this archive");
+  else if (res == (SZ_RESULT)SZE_OUTOFMEMORY)
+    PrintError("can not allocate memory");
+  else if (res == (SZ_RESULT)SZE_CRC_ERROR)
+    PrintError("CRC error");
+  else     
+    printf("\nERROR #%d\n", res);
+  return 1;
+}

+ 10 - 0
lzma/C/Archive/7z/7zMethodID.c

@@ -0,0 +1,10 @@
+/* 7zMethodID.c */
+
+#include "7zMethodID.h"
+
+/*
+int AreMethodsEqual(CMethodID *a1, CMethodID *a2)
+{
+  return (*a1 == *a2) ? 1 : 0;
+}
+*/

+ 10 - 0
lzma/C/Archive/7z/7zMethodID.h

@@ -0,0 +1,10 @@
+/* 7zMethodID.h */
+
+#ifndef __7Z_METHOD_ID_H
+#define __7Z_METHOD_ID_H
+
+#include "../../Types.h"
+
+typedef UInt64 CMethodID;
+
+#endif

+ 211 - 0
lzma/C/Archive/7z/7z_C.dsp

@@ -0,0 +1,211 @@
+# Microsoft Developer Studio Project File - Name="7z_C" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=7z_C - 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 "7z_C.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 "7z_C.mak" CFG="7z_C - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "7z_C - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "7z_C - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "7z_C - 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 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W4 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_LZMA_PROB32" /D "_LZMA_IN_CB" /YX /FD /c
+# 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 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 /subsystem:console /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 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 /subsystem:console /machine:I386 /out:"Release/7zDec.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "7z_C - 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 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W4 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_LZMA_PROB32" /D "_LZMA_IN_CB" /YX /FD /GZ /c
+# 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 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 /subsystem:console /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 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 /subsystem:console /debug /machine:I386 /out:"Debug/7zDec.exe" /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "7z_C - Win32 Release"
+# Name "7z_C - Win32 Debug"
+# Begin Group "LZMA"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma\LzmaDecode.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma\LzmaDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma\LzmaTypes.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\7zCrc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Types.h
+# End Source File
+# End Group
+# Begin Group "Branch"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Branch\BranchTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Branch\BranchX86.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Branch\BranchX86.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Branch\BranchX86_2.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Branch\BranchX86_2.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\7zAlloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zAlloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zBuffer.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zDecode.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zExtract.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zExtract.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zHeader.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zIn.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zItem.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zMain.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zMethodID.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zMethodID.h
+# End Source File
+# End Target
+# End Project

+ 29 - 0
lzma/C/Archive/7z/7z_C.dsw

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

+ 74 - 0
lzma/C/Archive/7z/makefile

@@ -0,0 +1,74 @@
+PROG = 7zDec.exe
+
+!IFDEF CPU
+LIBS = $(LIBS) bufferoverflowU.lib 
+CFLAGS = $(CFLAGS) -GS- -Zc:forScope -WX -GS- -Gy -W4 
+!ENDIF
+
+!IFNDEF O
+!IFDEF CPU
+O=$(CPU)
+!ELSE
+O=O
+!ENDIF
+!ENDIF
+
+CFLAGS = $(CFLAGS) -nologo -c -Fo$O/ -D_LZMA_IN_CB
+CFLAGS_O1 = $(CFLAGS) -O1
+CFLAGS_O2 = $(CFLAGS) -O2
+
+LFLAGS = $(LFLAGS) -nologo -OPT:NOWIN98 -OPT:REF
+
+PROGPATH = $O\$(PROG)
+
+COMPL_O1   = $(CPP) $(CFLAGS_O1) $**
+COMPL_O2   = $(CPP) $(CFLAGS_O2) $**
+COMPL      = $(CPP) $(CFLAGS_O1) $**
+
+C_OBJS = \
+  $O\7zCrc.obj \
+
+
+7Z_OBJS = \
+  $O\7zAlloc.obj \
+  $O\7zBuffer.obj \
+  $O\7zDecode.obj \
+  $O\7zExtract.obj \
+  $O\7zHeader.obj \
+  $O\7zIn.obj \
+  $O\7zItem.obj \
+  $O\7zMain.obj \
+  $O\7zMethodID.obj \
+
+OBJS = \
+  $(7Z_OBJS) \
+  $O\LzmaDecode.obj \
+  $O\BranchX86.obj \
+  $O\BranchX86_2.obj \
+  $(C_OBJS) \
+
+all: $(PROGPATH) 
+
+clean:
+	-del /Q $(PROGPATH) $O\*.exe $O\*.dll $O\*.obj $O\*.lib $O\*.exp $O\*.res $O\*.pch 
+
+$O:
+	if not exist "$O" mkdir "$O"
+
+$(PROGPATH): $O $(OBJS)
+	link $(LFLAGS) -out:$(PROGPATH) $(OBJS) $(LIBS)
+
+
+$(7Z_OBJS): $(*B).c
+	$(COMPL)
+$O\LzmaDecode.obj: ../../Compress/Lzma/$(*B).c
+	$(COMPL_O2)
+
+$O\BranchX86.obj: ../../Compress/Branch/$(*B).c
+	$(COMPL_O2)
+
+$O\BranchX86_2.obj: ../../Compress/Branch/$(*B).c
+	$(COMPL_O2)
+
+$(C_OBJS): ../../$(*B).c
+	$(COMPL_O2)

+ 55 - 0
lzma/C/Archive/7z/makefile.gcc

@@ -0,0 +1,55 @@
+PROG = 7zDec
+CXX = g++
+LIB = 
+RM = rm -f
+CFLAGS = -c -O2 -Wall -D_LZMA_IN_CB
+
+OBJS = 7zAlloc.o 7zBuffer.o 7zCrc.o 7zDecode.o 7zExtract.o 7zHeader.o 7zIn.o 7zItem.o 7zMain.o 7zMethodID.o LzmaDecode.o BranchX86.o BranchX86_2.o
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+	$(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB)
+
+7zAlloc.o: 7zAlloc.c
+	$(CXX) $(CFLAGS) 7zAlloc.c
+
+7zBuffer.o: 7zBuffer.c
+	$(CXX) $(CFLAGS) 7zBuffer.c
+
+7zCrc.o: ../../7zCrc.c
+	$(CXX) $(CFLAGS) ../../7zCrc.c
+
+7zDecode.o: 7zDecode.c
+	$(CXX) $(CFLAGS) 7zDecode.c
+
+7zExtract.o: 7zExtract.c
+	$(CXX) $(CFLAGS) 7zExtract.c
+
+7zHeader.o: 7zHeader.c
+	$(CXX) $(CFLAGS) 7zHeader.c
+
+7zIn.o: 7zIn.c
+	$(CXX) $(CFLAGS) 7zIn.c
+
+7zItem.o: 7zItem.c
+	$(CXX) $(CFLAGS) 7zItem.c
+
+7zMain.o: 7zMain.c
+	$(CXX) $(CFLAGS) 7zMain.c
+
+7zMethodID.o: 7zMethodID.c
+	$(CXX) $(CFLAGS) 7zMethodID.c
+
+LzmaDecode.o: ../../Compress/Lzma/LzmaDecode.c
+	$(CXX) $(CFLAGS) ../../Compress/Lzma/LzmaDecode.c
+
+BranchX86.o: ../../Compress/Branch/BranchX86.c
+	$(CXX) $(CFLAGS) ../../Compress/Branch/BranchX86.c
+
+BranchX86_2.o: ../../Compress/Branch/BranchX86_2.c
+	$(CXX) $(CFLAGS) ../../Compress/Branch/BranchX86_2.c
+
+clean:
+	-$(RM) $(PROG) $(OBJS)
+

+ 26 - 0
lzma/C/Compress/Branch/BranchARM.c

@@ -0,0 +1,26 @@
+/* BranchARM.c */
+
+#include "BranchARM.h"
+
+UInt32 ARM_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
+{
+  UInt32 i;
+  for (i = 0; i + 4 <= size; i += 4)
+  {
+    if (data[i + 3] == 0xEB)
+    {
+      UInt32 dest;
+      UInt32 src = (data[i + 2] << 16) | (data[i + 1] << 8) | (data[i + 0]);
+      src <<= 2;
+      if (encoding)
+        dest = nowPos + i + 8 + src;
+      else
+        dest = src - (nowPos + i + 8);
+      dest >>= 2;
+      data[i + 2] = (Byte)(dest >> 16);
+      data[i + 1] = (Byte)(dest >> 8);
+      data[i + 0] = (Byte)dest;
+    }
+  }
+  return i;
+}

+ 10 - 0
lzma/C/Compress/Branch/BranchARM.h

@@ -0,0 +1,10 @@
+/* BranchARM.h */
+
+#ifndef __BRANCH_ARM_H
+#define __BRANCH_ARM_H
+
+#include "BranchTypes.h"
+
+UInt32 ARM_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
+
+#endif

+ 35 - 0
lzma/C/Compress/Branch/BranchARMThumb.c

@@ -0,0 +1,35 @@
+/* BranchARMThumb.c */
+
+#include "BranchARMThumb.h"
+
+UInt32 ARMThumb_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
+{
+  UInt32 i;
+  for (i = 0; i + 4 <= size; i += 2)
+  {
+    if ((data[i + 1] & 0xF8) == 0xF0 && 
+        (data[i + 3] & 0xF8) == 0xF8)
+    {
+      UInt32 dest;
+      UInt32 src = 
+        ((data[i + 1] & 0x7) << 19) |
+        (data[i + 0] << 11) |
+        ((data[i + 3] & 0x7) << 8) |
+        (data[i + 2]);
+      
+      src <<= 1;
+      if (encoding)
+        dest = nowPos + i + 4 + src;
+      else
+        dest = src - (nowPos + i + 4);
+      dest >>= 1;
+      
+      data[i + 1] = (Byte)(0xF0 | ((dest >> 19) & 0x7));
+      data[i + 0] = (Byte)(dest >> 11);
+      data[i + 3] = (Byte)(0xF8 | ((dest >> 8) & 0x7));
+      data[i + 2] = (Byte)dest;
+      i += 2;
+    }
+  }
+  return i;
+}

+ 10 - 0
lzma/C/Compress/Branch/BranchARMThumb.h

@@ -0,0 +1,10 @@
+/* BranchARMThumb.h */
+
+#ifndef __BRANCH_ARM_THUMB_H
+#define __BRANCH_ARM_THUMB_H
+
+#include "BranchTypes.h"
+
+UInt32 ARMThumb_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
+
+#endif

+ 66 - 0
lzma/C/Compress/Branch/BranchIA64.c

@@ -0,0 +1,66 @@
+/* BranchIA64.c */
+
+#include "BranchIA64.h"
+
+const Byte kBranchTable[32] = 
+{ 
+  0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,
+  4, 4, 6, 6, 0, 0, 7, 7,
+  4, 4, 0, 0, 4, 4, 0, 0 
+};
+
+UInt32 IA64_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
+{
+  UInt32 i;
+  for (i = 0; i + 16 <= size; i += 16)
+  {
+    UInt32 instrTemplate = data[i] & 0x1F;
+    UInt32 mask = kBranchTable[instrTemplate];
+    UInt32 bitPos = 5;
+    int slot;
+    for (slot = 0; slot < 3; slot++, bitPos += 41)
+    {
+      UInt32 bytePos, bitRes;
+      UInt64 instruction, instNorm;
+      int j;
+      if (((mask >> slot) & 1) == 0)
+        continue;
+      bytePos = (bitPos >> 3);
+      bitRes = bitPos & 0x7;
+      instruction = 0;
+      for (j = 0; j < 6; j++)
+        instruction += (UInt64)(data[i + j + bytePos]) << (8 * j);
+
+      instNorm = instruction >> bitRes;
+      if (((instNorm >> 37) & 0xF) == 0x5 
+        &&  ((instNorm >> 9) & 0x7) == 0 
+        /* &&  (instNorm & 0x3F)== 0 */
+        )
+      {
+        UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF);
+        UInt32 dest;
+        src |= ((UInt32)(instNorm >> 36) & 1) << 20;
+        
+        src <<= 4;
+        
+        if (encoding)
+          dest = nowPos + i + src;
+        else
+          dest = src - (nowPos + i);
+        
+        dest >>= 4;
+        
+        instNorm &= ~((UInt64)(0x8FFFFF) << 13);
+        instNorm |= ((UInt64)(dest & 0xFFFFF) << 13);
+        instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20));
+        
+        instruction &= (1 << bitRes) - 1;
+        instruction |= (instNorm << bitRes);
+        for (j = 0; j < 6; j++)
+          data[i + j + bytePos] = (Byte)(instruction >> (8 * j));
+      }
+    }
+  }
+  return i;
+}

+ 10 - 0
lzma/C/Compress/Branch/BranchIA64.h

@@ -0,0 +1,10 @@
+/* BranchIA64.h */
+
+#ifndef __BRANCH_IA64_H
+#define __BRANCH_IA64_H
+
+#include "BranchTypes.h"
+
+UInt32 IA64_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
+
+#endif

+ 36 - 0
lzma/C/Compress/Branch/BranchPPC.c

@@ -0,0 +1,36 @@
+/* BranchPPC.c */
+
+#include "BranchPPC.h"
+
+UInt32 PPC_B_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
+{
+  UInt32 i;
+  for (i = 0; i + 4 <= size; i += 4)
+  {
+    /* PowerPC branch 6(48) 24(Offset) 1(Abs) 1(Link) */
+    if ((data[i] >> 2) == 0x12 && 
+    (
+      (data[i + 3] & 3) == 1 
+      /* || (data[i+3] & 3) == 3 */
+      )
+    )
+    {
+      UInt32 src = ((data[i + 0] & 3) << 24) |
+        (data[i + 1] << 16) |
+        (data[i + 2] << 8) |
+        (data[i + 3] & (~3));
+      
+      UInt32 dest;
+      if (encoding)
+        dest = nowPos + i + src;
+      else
+        dest = src - (nowPos + i);
+      data[i + 0] = (Byte)(0x48 | ((dest >> 24) &  0x3));
+      data[i + 1] = (Byte)(dest >> 16);
+      data[i + 2] = (Byte)(dest >> 8);
+      data[i + 3] &= 0x3;
+      data[i + 3] |= dest;
+    }
+  }
+  return i;
+}

+ 10 - 0
lzma/C/Compress/Branch/BranchPPC.h

@@ -0,0 +1,10 @@
+/* BranchPPC.h */
+
+#ifndef __BRANCH_PPC_H
+#define __BRANCH_PPC_H
+
+#include "BranchTypes.h"
+
+UInt32 PPC_B_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
+
+#endif

+ 36 - 0
lzma/C/Compress/Branch/BranchSPARC.c

@@ -0,0 +1,36 @@
+/* BranchSPARC.c */
+
+#include "BranchSPARC.h"
+
+UInt32 SPARC_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
+{
+  UInt32 i;
+  for (i = 0; i + 4 <= size; i += 4)
+  {
+    if (data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00 || 
+        data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0)
+    {
+      UInt32 src = 
+        ((UInt32)data[i + 0] << 24) |
+        ((UInt32)data[i + 1] << 16) |
+        ((UInt32)data[i + 2] << 8) |
+        ((UInt32)data[i + 3]);
+      UInt32 dest;
+      
+      src <<= 2;
+      if (encoding)
+        dest = nowPos + i + src;
+      else
+        dest = src - (nowPos + i);
+      dest >>= 2;
+      
+      dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF) | (dest & 0x3FFFFF) | 0x40000000;
+
+      data[i + 0] = (Byte)(dest >> 24);
+      data[i + 1] = (Byte)(dest >> 16);
+      data[i + 2] = (Byte)(dest >> 8);
+      data[i + 3] = (Byte)dest;
+    }
+  }
+  return i;
+}

+ 10 - 0
lzma/C/Compress/Branch/BranchSPARC.h

@@ -0,0 +1,10 @@
+/* BranchSPARC.h */
+
+#ifndef __BRANCH_SPARC_H
+#define __BRANCH_SPARC_H
+
+#include "BranchTypes.h"
+
+UInt32 SPARC_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
+
+#endif

+ 51 - 0
lzma/C/Compress/Branch/BranchTypes.h

@@ -0,0 +1,51 @@
+/* BranchTypes.h */
+
+#ifndef __BRANCHTYPES_H
+#define __BRANCHTYPES_H
+
+#ifndef _7ZIP_BYTE_DEFINED
+#define _7ZIP_BYTE_DEFINED
+typedef unsigned char Byte;
+#endif 
+
+#ifndef _7ZIP_UINT16_DEFINED
+#define _7ZIP_UINT16_DEFINED
+typedef unsigned short UInt16;
+#endif 
+
+#ifndef _7ZIP_UINT32_DEFINED
+#define _7ZIP_UINT32_DEFINED
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef unsigned long UInt32;
+#else
+typedef unsigned int UInt32;
+#endif
+#endif
+
+#ifndef _7ZIP_UINT64_DEFINED
+#define _7ZIP_UINT64_DEFINED
+#ifdef _SZ_NO_INT_64
+typedef unsigned long UInt64;
+#else
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef unsigned __int64 UInt64;
+#else
+typedef unsigned long long int UInt64;
+#endif
+#endif
+#endif
+
+/* #define _LZMA_NO_SYSTEM_SIZE_T */
+/* You can use it, if you don't want <stddef.h> */
+
+#ifndef _7ZIP_SIZET_DEFINED
+#define _7ZIP_SIZET_DEFINED
+#ifdef _LZMA_NO_SYSTEM_SIZE_T
+typedef UInt32 SizeT;
+#else
+#include <stddef.h>
+typedef size_t SizeT;
+#endif
+#endif
+
+#endif

+ 84 - 0
lzma/C/Compress/Branch/BranchX86.c

@@ -0,0 +1,84 @@
+/* BranchX86.c */
+
+#include "BranchX86.h"
+
+#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
+
+const Byte kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
+const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};
+
+SizeT x86_Convert(Byte *buffer, SizeT endPos, UInt32 nowPos, UInt32 *prevMaskMix, int encoding)
+{
+  SizeT bufferPos = 0, prevPosT;
+  UInt32 prevMask = *prevMaskMix & 0x7;
+  if (endPos < 5)
+    return 0;
+  nowPos += 5;
+  prevPosT = (SizeT)0 - 1;
+
+  for(;;)
+  {
+    Byte *p = buffer + bufferPos;
+    Byte *limit = buffer + endPos - 4;
+    for (; p < limit; p++)
+      if ((*p & 0xFE) == 0xE8)
+        break;
+    bufferPos = (SizeT)(p - buffer);
+    if (p >= limit)
+      break;
+    prevPosT = bufferPos - prevPosT;
+    if (prevPosT > 3)
+      prevMask = 0;
+    else
+    {
+      prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;
+      if (prevMask != 0)
+      {
+        Byte b = p[4 - kMaskToBitNumber[prevMask]];
+        if (!kMaskToAllowedStatus[prevMask] || Test86MSByte(b))
+        {
+          prevPosT = bufferPos;
+          prevMask = ((prevMask << 1) & 0x7) | 1;
+          bufferPos++;
+          continue;
+        }
+      }
+    }
+    prevPosT = bufferPos;
+
+    if (Test86MSByte(p[4]))
+    {
+      UInt32 src = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]);
+      UInt32 dest;
+      for (;;)
+      {
+        Byte b;
+        int index;
+        if (encoding)
+          dest = (nowPos + (UInt32)bufferPos) + src;
+        else
+          dest = src - (nowPos + (UInt32)bufferPos);
+        if (prevMask == 0)
+          break;
+        index = kMaskToBitNumber[prevMask] * 8;
+        b = (Byte)(dest >> (24 - index));
+        if (!Test86MSByte(b))
+          break;
+        src = dest ^ ((1 << (32 - index)) - 1);
+      }
+      p[4] = (Byte)(~(((dest >> 24) & 1) - 1));
+      p[3] = (Byte)(dest >> 16);
+      p[2] = (Byte)(dest >> 8);
+      p[1] = (Byte)dest;
+      bufferPos += 5;
+    }
+    else
+    {
+      prevMask = ((prevMask << 1) & 0x7) | 1;
+      bufferPos++;
+    }
+  }
+  prevPosT = bufferPos - prevPosT;
+  *prevMaskMix = ((prevPosT > 3) ? 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7));
+  return bufferPos;
+}

+ 12 - 0
lzma/C/Compress/Branch/BranchX86.h

@@ -0,0 +1,12 @@
+/* BranchX86.h */
+
+#ifndef __BRANCHX86_H
+#define __BRANCHX86_H
+
+#include "BranchTypes.h"
+
+#define x86_Convert_Init(state) { state = 0; }
+
+SizeT x86_Convert(Byte *buffer, SizeT endPos, UInt32 nowPos, UInt32 *state, int encoding);
+
+#endif

+ 135 - 0
lzma/C/Compress/Branch/BranchX86_2.c

@@ -0,0 +1,135 @@
+// BranchX86_2.c
+
+#include "BranchX86_2.h"
+
+#include "../../Alloc.h"
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb UInt16
+#endif
+
+#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80)
+#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1))
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
+  { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
+
+#define RC_TEST { if (Buffer == BufferLim) return BCJ2_RESULT_DATA_ERROR; }
+
+#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
+ 
+#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+// #define UpdateBit0(p) Range = bound; *(p) = (CProb)(*(p) + ((kBitModelTotal - *(p)) >> kNumMoveBits));
+// #define UpdateBit1(p) Range -= bound; Code -= bound; *(p) = (CProb)(*(p) - (*(p) >> kNumMoveBits));
+
+int x86_2_Decode(
+    const Byte *buf0, SizeT size0, 
+    const Byte *buf1, SizeT size1, 
+    const Byte *buf2, SizeT size2, 
+    const Byte *buf3, SizeT size3, 
+    Byte *outBuf, SizeT outSize)
+{
+  CProb p[256 + 2];
+  SizeT inPos = 0, outPos = 0;
+
+  const Byte *Buffer, *BufferLim;
+  UInt32 Range, Code;
+  Byte prevByte = 0;
+
+  unsigned int i;
+  for (i = 0; i < sizeof(p) / sizeof(p[0]); i++)
+    p[i] = kBitModelTotal >> 1; 
+  RC_INIT(buf3, size3);
+
+  if (outSize == 0)
+    return BCJ2_RESULT_OK;
+
+  for (;;)
+  {
+    Byte b;
+    CProb *prob;
+    UInt32 bound;
+
+    SizeT limit = size0 - inPos;
+    if (outSize - outPos < limit)
+      limit = outSize - outPos;
+    while (limit != 0)
+    {
+      Byte b = buf0[inPos];
+      outBuf[outPos++] = b;
+      if (IsJ(prevByte, b))
+        break;
+      inPos++;
+      prevByte = b;
+      limit--;
+    }
+
+    if (limit == 0 || outPos == outSize)
+      break;
+
+    b = buf0[inPos++];
+
+    if (b == 0xE8)
+      prob = p + prevByte;
+    else if (b == 0xE9)
+      prob = p + 256;
+    else
+      prob = p + 257;
+
+    IfBit0(prob)
+    {
+      UpdateBit0(prob)
+      prevByte = b;
+    }
+    else
+    {
+      UInt32 dest;
+      const Byte *v;
+      UpdateBit1(prob)
+      if (b == 0xE8)
+      {
+        v = buf1;
+        if (size1 < 4)
+          return BCJ2_RESULT_DATA_ERROR;
+        buf1 += 4;
+        size1 -= 4;
+      }
+      else
+      {
+        v = buf2;
+        if (size2 < 4)
+          return BCJ2_RESULT_DATA_ERROR;
+        buf2 += 4;
+        size2 -= 4;
+      }
+      dest = (((UInt32)v[0] << 24) | ((UInt32)v[1] << 16) | 
+          ((UInt32)v[2] << 8) | ((UInt32)v[3])) - ((UInt32)outPos + 4);
+      outBuf[outPos++] = (Byte)dest;
+      if (outPos == outSize)
+        break;
+      outBuf[outPos++] = (Byte)(dest >> 8);
+      if (outPos == outSize)
+        break;
+      outBuf[outPos++] = (Byte)(dest >> 16);
+      if (outPos == outSize)
+        break;
+      outBuf[outPos++] = prevByte = (Byte)(dest >> 24);
+    }
+  }
+  return (outPos == outSize) ? BCJ2_RESULT_OK : BCJ2_RESULT_DATA_ERROR;
+}

+ 28 - 0
lzma/C/Compress/Branch/BranchX86_2.h

@@ -0,0 +1,28 @@
+// BranchX86_2.h
+
+#ifndef __BRANCHX86_2_H
+#define __BRANCHX86_2_H
+
+#include "BranchTypes.h"
+
+#define BCJ2_RESULT_OK 0
+#define BCJ2_RESULT_DATA_ERROR 1
+
+/*
+Conditions:
+  outSize <= FullOutputSize, 
+  where FullOutputSize is full size of output stream of x86_2 filter.
+
+If buf0 overlaps outBuf, there are two required conditions:
+  1) (buf0 >= outBuf)
+  2) (buf0 + size0 >= outBuf + FullOutputSize).
+*/
+
+int x86_2_Decode(
+    const Byte *buf0, SizeT size0, 
+    const Byte *buf1, SizeT size1, 
+    const Byte *buf2, SizeT size2, 
+    const Byte *buf3, SizeT size3, 
+    Byte *outBuf, SizeT outSize);
+
+#endif

+ 146 - 0
lzma/C/Compress/Huffman/HuffmanEncode.c

@@ -0,0 +1,146 @@
+/* Compress/HuffmanEncode.c */
+
+#include "HuffmanEncode.h"
+#include "../../Sort.h"
+
+#define kMaxLen 16
+#define NUM_BITS 10
+#define MASK ((1 << NUM_BITS) - 1)
+
+#define NUM_COUNTERS 64
+
+/* use BLOCK_SORT_EXTERNAL_FLAGS if blockSize > 1M */
+#define HUFFMAN_SPEED_OPT
+
+void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymbols, UInt32 maxLen)
+{
+  UInt32 num = 0;
+  /* if (maxLen > 10) maxLen = 10; */
+  {
+    UInt32 i;
+    
+    #ifdef HUFFMAN_SPEED_OPT
+    
+    UInt32 counters[NUM_COUNTERS];
+    for (i = 0; i < NUM_COUNTERS; i++) 
+      counters[i] = 0;
+    for (i = 0; i < numSymbols; i++) 
+    {
+      UInt32 freq = freqs[i];
+      counters[(freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1]++;
+    }
+ 
+    for (i = 1; i < NUM_COUNTERS; i++) 
+    {
+      UInt32 temp = counters[i];
+      counters[i] = num;
+      num += temp;
+    }
+
+    for (i = 0; i < numSymbols; i++) 
+    {
+      UInt32 freq = freqs[i];
+      if (freq == 0)
+        lens[i] = 0;
+      else
+        p[counters[((freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1)]++] = i | (freq << NUM_BITS);
+    }
+    counters[0] = 0;
+    HeapSort(p + counters[NUM_COUNTERS - 2], counters[NUM_COUNTERS - 1] - counters[NUM_COUNTERS - 2]);
+    
+    #else
+
+    for (i = 0; i < numSymbols; i++) 
+    {
+      UInt32 freq = freqs[i];
+      if (freq == 0)
+        lens[i] = 0;
+      else
+        p[num++] = i | (freq << NUM_BITS);
+    }
+    HeapSort(p, num);
+
+    #endif
+  }
+
+  if (num < 2) 
+  {
+    int minCode = 0;
+    int maxCode = 1;
+    if (num == 1)
+    {
+      maxCode = p[0] & MASK;
+      if (maxCode == 0)
+        maxCode++;
+    }
+    p[minCode] = 0;
+    p[maxCode] = 1;
+    lens[minCode] = lens[maxCode] = 1;
+    return;
+  }
+  
+  {
+    UInt32 b, e, i;
+  
+    i = b = e = 0;
+    do 
+    {
+      UInt32 n, m, freq;
+      n = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++;
+      freq = (p[n] & ~MASK);
+      p[n] = (p[n] & MASK) | (e << NUM_BITS);
+      m = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++;
+      freq += (p[m] & ~MASK);
+      p[m] = (p[m] & MASK) | (e << NUM_BITS);
+      p[e] = (p[e] & MASK) | freq;
+      e++;
+    } 
+    while (num - e > 1);
+    
+    {
+      UInt32 lenCounters[kMaxLen + 1];
+      for (i = 0; i <= kMaxLen; i++) 
+        lenCounters[i] = 0;
+      
+      p[--e] &= MASK;
+      lenCounters[1] = 2;
+      while (e > 0) 
+      {
+        UInt32 len = (p[p[--e] >> NUM_BITS] >> NUM_BITS) + 1;
+        p[e] = (p[e] & MASK) | (len << NUM_BITS);
+        if (len >= maxLen) 
+          for (len = maxLen - 1; lenCounters[len] == 0; len--);
+        lenCounters[len]--;
+        lenCounters[len + 1] += 2;
+      }
+      
+      {
+        UInt32 len;
+        i = 0;
+        for (len = maxLen; len != 0; len--) 
+        {
+          UInt32 num;
+          for (num = lenCounters[len]; num != 0; num--) 
+            lens[p[i++] & MASK] = (Byte)len;
+        }
+      }
+      
+      {
+        UInt32 nextCodes[kMaxLen + 1];
+        {
+          UInt32 code = 0;
+          UInt32 len;
+          for (len = 1; len <= kMaxLen; len++) 
+            nextCodes[len] = code = (code + lenCounters[len - 1]) << 1;
+        }
+        /* if (code + lenCounters[kMaxLen] - 1 != (1 << kMaxLen) - 1) throw 1; */
+
+        {
+          UInt32 i;
+          for (i = 0; i < numSymbols; i++) 
+            p[i] = nextCodes[lens[i]]++;
+        }
+      }
+    }
+  }
+}

+ 18 - 0
lzma/C/Compress/Huffman/HuffmanEncode.h

@@ -0,0 +1,18 @@
+/* Compress/HuffmanEncode.h */
+
+#ifndef __COMPRESS_HUFFMANENCODE_H
+#define __COMPRESS_HUFFMANENCODE_H
+
+#include "../../Types.h"
+
+/*
+Conditions:
+  num <= 1024 = 2 ^ NUM_BITS
+  Sum(freqs) < 4M = 2 ^ (32 - NUM_BITS)
+  maxLen <= 16 = kMaxLen
+  Num_Items(p) >= HUFFMAN_TEMP_SIZE(num)
+*/
+ 
+void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 num, UInt32 maxLen);
+
+#endif

+ 53 - 0
lzma/C/Compress/Lz/LzHash.h

@@ -0,0 +1,53 @@
+/* LzHash.h */
+
+#ifndef __C_LZHASH_H
+#define __C_LZHASH_H
+
+#define kHash2Size (1 << 10)
+#define kHash3Size (1 << 16)
+#define kHash4Size (1 << 20)
+
+#define kFix3HashSize (kHash2Size)
+#define kFix4HashSize (kHash2Size + kHash3Size)
+#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
+
+#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
+
+#define HASH3_CALC { \
+  UInt32 temp = g_CrcTable[cur[0]] ^ cur[1]; \
+  hash2Value = temp & (kHash2Size - 1); \
+  hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
+
+#define HASH4_CALC { \
+  UInt32 temp = g_CrcTable[cur[0]] ^ cur[1]; \
+  hash2Value = temp & (kHash2Size - 1); \
+  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+  hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (g_CrcTable[cur[3]] << 5)) & p->hashMask; }
+
+#define HASH5_CALC { \
+  UInt32 temp = g_CrcTable[cur[0]] ^ cur[1]; \
+  hash2Value = temp & (kHash2Size - 1); \
+  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+  hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (g_CrcTable[cur[3]] << 5)); \
+  hashValue = (hash4Value ^ (g_CrcTable[cur[4]] << 3)) & p->hashMask; \
+  hash4Value &= (kHash4Size - 1); }
+
+/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ g_CrcTable[cur[2]]) & 0xFFFF; */
+#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ g_CrcTable[cur[1]]) & 0xFFFF;
+
+
+#define MT_HASH2_CALC \
+  hash2Value = (g_CrcTable[cur[0]] ^ cur[1]) & (kHash2Size - 1);
+
+#define MT_HASH3_CALC { \
+  UInt32 temp = g_CrcTable[cur[0]] ^ cur[1]; \
+  hash2Value = temp & (kHash2Size - 1); \
+  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
+
+#define MT_HASH4_CALC { \
+  UInt32 temp = g_CrcTable[cur[0]] ^ cur[1]; \
+  hash2Value = temp & (kHash2Size - 1); \
+  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+  hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (g_CrcTable[cur[3]] << 5)) & (kHash4Size - 1); }
+
+#endif

+ 742 - 0
lzma/C/Compress/Lz/MatchFinder.c

@@ -0,0 +1,742 @@
+/* MatchFinder.c */
+/* Please call InitCrcTable before */
+
+#include <string.h>
+
+#include "MatchFinder.h"
+#include "LzHash.h"
+
+#include "../../7zCrc.h"
+
+#define kEmptyHashValue 0
+#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
+#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
+#define kNormalizeMask (~(kNormalizeStepMin - 1))
+#define kMaxHistorySize ((UInt32)3 << 30)
+
+#define kStartMaxLen 3
+
+void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
+{
+  if (!p->directInput)
+  {
+    alloc->Free(p->bufferBase);
+    p->bufferBase = 0;
+  }
+}
+
+/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
+
+int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
+{
+  UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
+  if (p->directInput)
+  {
+    p->blockSize = blockSize;
+    return 1;
+  }
+  if (p->bufferBase == 0 || p->blockSize != blockSize)
+  {
+    LzInWindow_Free(p, alloc);
+    p->blockSize = blockSize;
+    p->bufferBase = (Byte *)alloc->Alloc(blockSize);
+  }
+  return (p->bufferBase != 0);
+}
+
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
+Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
+
+UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
+
+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
+{
+  p->posLimit -= subValue;
+  p->pos -= subValue;
+  p->streamPos -= subValue;
+}
+
+void MatchFinder_ReadBlock(CMatchFinder *p)
+{
+  if (p->streamEndWasReached || p->result != SZ_OK)
+    return;
+  for (;;)
+  {
+    Byte *dest = p->buffer + (p->streamPos - p->pos);
+    UInt32 numReadBytes;
+    UInt32 size = (UInt32)(p->bufferBase + p->blockSize - dest);
+    if (size == 0)
+      return;
+    p->result = p->stream->Read(p->stream, dest, size, &numReadBytes);
+    if (p->result != SZ_OK)
+      return;
+    if (numReadBytes == 0)
+    {
+      p->streamEndWasReached = 1;
+      return;
+    }
+    p->streamPos += numReadBytes;
+    if (p->streamPos - p->pos > p->keepSizeAfter)
+      return;
+  }
+}
+
+void MatchFinder_MoveBlock(CMatchFinder *p)
+{
+  memmove(p->bufferBase, 
+    p->buffer - p->keepSizeBefore, 
+    p->streamPos - p->pos + p->keepSizeBefore);
+  p->buffer = p->bufferBase + p->keepSizeBefore;
+}
+
+int MatchFinder_NeedMove(CMatchFinder *p)
+{
+  /* if (p->streamEndWasReached) return 0; */
+  return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
+}
+
+void MatchFinder_ReadIfRequired(CMatchFinder *p)
+{
+  if (p->streamEndWasReached) 
+    return;
+  if (p->keepSizeAfter >= p->streamPos - p->pos)
+    MatchFinder_ReadBlock(p);
+}
+
+void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
+{
+  if (MatchFinder_NeedMove(p))
+    MatchFinder_MoveBlock(p);
+  MatchFinder_ReadBlock(p);
+}
+
+void MatchFinder_SetDefaultSettings(CMatchFinder *p)
+{
+  p->cutValue = 32;
+  p->btMode = 1;
+  p->numHashBytes = 4;
+  /* p->skipModeBits = 0; */
+  p->directInput = 0;
+  p->bigHash = 0;
+}
+
+void MatchFinder_Construct(CMatchFinder *p)
+{
+  p->bufferBase = 0;
+  p->directInput = 0;
+  p->hash = 0;
+  MatchFinder_SetDefaultSettings(p);
+}
+
+void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
+{
+  alloc->Free(p->hash);
+  p->hash = 0;
+}
+
+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
+{
+  MatchFinder_FreeThisClassMemory(p, alloc);
+  LzInWindow_Free(p, alloc);
+}
+
+CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
+{
+  size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
+  if (sizeInBytes / sizeof(CLzRef) != num)
+    return 0;
+  return (CLzRef *)alloc->Alloc(sizeInBytes);
+}
+
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, 
+    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+    ISzAlloc *alloc)
+{
+  UInt32 sizeReserv;
+  if (historySize > kMaxHistorySize)
+  {
+    MatchFinder_Free(p, alloc);
+    return 0;
+  }
+  sizeReserv = historySize >> 1;
+  if (historySize > ((UInt32)2 << 30))
+    sizeReserv = historySize >> 2;
+  sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
+
+  p->keepSizeBefore = historySize + keepAddBufferBefore + 1; 
+  p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
+  /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
+  if (LzInWindow_Create(p, sizeReserv, alloc))
+  {
+    UInt32 newCyclicBufferSize = (historySize /* >> p->skipModeBits */) + 1;
+    UInt32 hs;
+    p->matchMaxLen = matchMaxLen;
+    {
+      p->fixedHashSize = 0;
+      if (p->numHashBytes == 2)
+        hs = (1 << 16) - 1;
+      else
+      {
+        hs = historySize - 1;
+        hs |= (hs >> 1);
+        hs |= (hs >> 2);
+        hs |= (hs >> 4);
+        hs |= (hs >> 8);
+        hs >>= 1;
+        /* hs >>= p->skipModeBits; */
+        hs |= 0xFFFF; /* don't change it! It's required for Deflate */
+        if (hs > (1 << 24))
+        {
+          if (p->numHashBytes == 3)
+            hs = (1 << 24) - 1;
+          else
+            hs >>= 1;
+        }
+      }
+      p->hashMask = hs;
+      hs++;
+      if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
+      if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
+      if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
+      hs += p->fixedHashSize;
+    }
+
+    {
+      UInt32 prevSize = p->hashSizeSum + p->numSons;
+      UInt32 newSize;
+      p->historySize = historySize;
+      p->hashSizeSum = hs;
+      p->cyclicBufferSize = newCyclicBufferSize;
+      p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
+      newSize = p->hashSizeSum + p->numSons;
+      if (p->hash != 0 && prevSize == newSize)
+        return 1;
+      MatchFinder_FreeThisClassMemory(p, alloc);
+      p->hash = AllocRefs(newSize, alloc);
+      if (p->hash != 0)
+      {
+        p->son = p->hash + p->hashSizeSum;
+        return 1;
+      }
+    }
+  }
+  MatchFinder_Free(p, alloc);
+  return 0;
+}
+
+void MatchFinder_SetLimits(CMatchFinder *p)
+{
+  UInt32 limit = kMaxValForNormalize - p->pos;
+  UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
+  if (limit2 < limit) 
+    limit = limit2;
+  limit2 = p->streamPos - p->pos;
+  if (limit2 <= p->keepSizeAfter)
+  {
+    if (limit2 > 0)
+      limit2 = 1;
+  }
+  else
+    limit2 -= p->keepSizeAfter;
+  if (limit2 < limit) 
+    limit = limit2;
+  {
+    UInt32 lenLimit = p->streamPos - p->pos;
+    if (lenLimit > p->matchMaxLen)
+      lenLimit = p->matchMaxLen;
+    p->lenLimit = lenLimit;
+  }
+  p->posLimit = p->pos + limit;
+}
+
+void MatchFinder_Init(CMatchFinder *p)
+{
+  UInt32 i;
+  for(i = 0; i < p->hashSizeSum; i++)
+    p->hash[i] = kEmptyHashValue;
+  p->cyclicBufferPos = 0;
+  p->buffer = p->bufferBase;
+  p->pos = p->streamPos = p->cyclicBufferSize;
+  p->result = SZ_OK;
+  p->streamEndWasReached = 0;
+  MatchFinder_ReadBlock(p);
+  MatchFinder_SetLimits(p);
+}
+
+UInt32 MatchFinder_GetSubValue(CMatchFinder *p) 
+{ 
+  return (p->pos - p->historySize - 1) & kNormalizeMask; 
+}
+
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
+{
+  UInt32 i;
+  for (i = 0; i < numItems; i++)
+  {
+    UInt32 value = items[i];
+    if (value <= subValue)
+      value = kEmptyHashValue;
+    else
+      value -= subValue;
+    items[i] = value;
+  }
+}
+
+void MatchFinder_Normalize(CMatchFinder *p)
+{
+  UInt32 subValue = MatchFinder_GetSubValue(p);
+  MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
+  MatchFinder_ReduceOffsets(p, subValue);
+}
+
+void MatchFinder_CheckLimits(CMatchFinder *p)
+{
+  if (p->pos == kMaxValForNormalize)
+    MatchFinder_Normalize(p);
+  if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
+    MatchFinder_CheckAndMoveAndRead(p);
+  if (p->cyclicBufferPos == p->cyclicBufferSize)
+    p->cyclicBufferPos = 0;
+  MatchFinder_SetLimits(p);
+}
+
+UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, 
+    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, 
+    UInt32 *distances, UInt32 maxLen)
+{
+  son[_cyclicBufferPos] = curMatch;
+  for (;;)
+  {
+    UInt32 delta = pos - curMatch;
+    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+      return distances;
+    {
+      const Byte *pb = cur - delta;
+      curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+      if (pb[maxLen] == cur[maxLen] && *pb == *cur)
+      {
+        UInt32 len = 0;
+        while(++len != lenLimit)
+          if (pb[len] != cur[len])
+            break;
+        if (maxLen < len)
+        {
+          *distances++ = maxLen = len;
+          *distances++ = delta - 1;
+          if (len == lenLimit)
+            return distances;
+        }
+      }
+    }
+  }
+}
+
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, 
+    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, 
+    UInt32 *distances, UInt32 maxLen)
+{
+  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+  UInt32 len0 = 0, len1 = 0;
+  for (;;)
+  {
+    UInt32 delta = pos - curMatch;
+    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+    {
+      *ptr0 = *ptr1 = kEmptyHashValue;
+      return distances;
+    }
+    {
+      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+      const Byte *pb = cur - delta;
+      UInt32 len = (len0 < len1 ? len0 : len1);
+      if (pb[len] == cur[len])
+      {
+        if (++len != lenLimit && pb[len] == cur[len])
+          while(++len != lenLimit)
+            if (pb[len] != cur[len])
+              break;
+        if (maxLen < len)
+        {
+          *distances++ = maxLen = len;
+          *distances++ = delta - 1;
+          if (len == lenLimit)
+          {
+            *ptr1 = pair[0];
+            *ptr0 = pair[1];
+            return distances;
+          }
+        }
+      }
+      if (pb[len] < cur[len])
+      {
+        *ptr1 = curMatch;
+        ptr1 = pair + 1;
+        curMatch = *ptr1;
+        len1 = len;
+      }
+      else
+      {
+        *ptr0 = curMatch;
+        ptr0 = pair;
+        curMatch = *ptr0;
+        len0 = len;
+      }
+    }
+  }
+}
+
+void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, 
+    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
+{
+  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+  UInt32 len0 = 0, len1 = 0;
+  for (;;)
+  {
+    UInt32 delta = pos - curMatch;
+    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+    {
+      *ptr0 = *ptr1 = kEmptyHashValue;
+      return;
+    }
+    {
+      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+      const Byte *pb = cur - delta;
+      UInt32 len = (len0 < len1 ? len0 : len1);
+      if (pb[len] == cur[len])
+      {
+        while(++len != lenLimit)
+          if (pb[len] != cur[len])
+            break;
+        {
+          if (len == lenLimit)
+          {
+            *ptr1 = pair[0];
+            *ptr0 = pair[1];
+            return;
+          }
+        }
+      }
+      if (pb[len] < cur[len])
+      {
+        *ptr1 = curMatch;
+        ptr1 = pair + 1;
+        curMatch = *ptr1;
+        len1 = len;
+      }
+      else
+      {
+        *ptr0 = curMatch;
+        ptr0 = pair;
+        curMatch = *ptr0;
+        len0 = len;
+      }
+    }
+  }
+}
+
+#define MOVE_POS \
+  ++p->cyclicBufferPos; \
+  p->buffer++; \
+  if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
+
+#define MOVE_POS_RET MOVE_POS return offset;
+
+void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
+
+#define GET_MATCHES_HEADER2(minLen, ret_op) \
+  UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
+  lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
+  cur = p->buffer;
+
+#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
+#define SKIP_HEADER(minLen)        GET_MATCHES_HEADER2(minLen, continue)
+
+#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
+
+#define GET_MATCHES_FOOTER(offset, maxLen) \
+  offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
+  distances + offset, maxLen) - distances); MOVE_POS_RET;
+
+#define SKIP_FOOTER \
+  SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
+
+UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 offset;
+  GET_MATCHES_HEADER(2)
+  HASH2_CALC;
+  curMatch = p->hash[hashValue];
+  p->hash[hashValue] = p->pos;
+  offset = 0;
+  GET_MATCHES_FOOTER(offset, 1)
+}
+
+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 offset;
+  GET_MATCHES_HEADER(3)
+  HASH_ZIP_CALC;
+  curMatch = p->hash[hashValue];
+  p->hash[hashValue] = p->pos;
+  offset = 0;
+  GET_MATCHES_FOOTER(offset, 2)
+}
+
+UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 hash2Value, delta2, maxLen, offset;
+  GET_MATCHES_HEADER(3)
+
+  HASH3_CALC;
+
+  delta2 = p->pos - p->hash[hash2Value];
+  curMatch = p->hash[kFix3HashSize + hashValue];
+  
+  p->hash[hash2Value] = 
+  p->hash[kFix3HashSize + hashValue] = p->pos;
+
+
+  maxLen = 2;
+  offset = 0;
+  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+  {
+    for (; maxLen != lenLimit; maxLen++)
+      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+        break;
+    distances[0] = maxLen;
+    distances[1] = delta2 - 1;
+    offset = 2;
+    if (maxLen == lenLimit)
+    {
+      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+      MOVE_POS_RET; 
+    }
+  }
+  GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+  GET_MATCHES_HEADER(4)
+
+  HASH4_CALC;
+
+  delta2 = p->pos - p->hash[                hash2Value];
+  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+  curMatch = p->hash[kFix4HashSize + hashValue];
+  
+  p->hash[                hash2Value] =
+  p->hash[kFix3HashSize + hash3Value] =
+  p->hash[kFix4HashSize + hashValue] = p->pos;
+
+  maxLen = 1;
+  offset = 0;
+  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+  {
+    distances[0] = maxLen = 2;
+    distances[1] = delta2 - 1;
+    offset = 2;
+  }
+  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+  {
+    maxLen = 3;
+    distances[offset + 1] = delta3 - 1;
+    offset += 2;
+    delta2 = delta3;
+  }
+  if (offset != 0)
+  {
+    for (; maxLen != lenLimit; maxLen++)
+      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+        break;
+    distances[offset - 2] = maxLen;
+    if (maxLen == lenLimit)
+    {
+      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+      MOVE_POS_RET; 
+    }
+  }
+  if (maxLen < 3)
+    maxLen = 3;
+  GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+  GET_MATCHES_HEADER(4)
+
+  HASH4_CALC;
+
+  delta2 = p->pos - p->hash[                hash2Value];
+  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+  curMatch = p->hash[kFix4HashSize + hashValue];
+
+  p->hash[                hash2Value] =
+  p->hash[kFix3HashSize + hash3Value] =
+  p->hash[kFix4HashSize + hashValue] = p->pos;
+
+  maxLen = 1;
+  offset = 0;
+  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+  {
+    distances[0] = maxLen = 2;
+    distances[1] = delta2 - 1;
+    offset = 2;
+  }
+  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+  {
+    maxLen = 3;
+    distances[offset + 1] = delta3 - 1;
+    offset += 2;
+    delta2 = delta3;
+  }
+  if (offset != 0)
+  {
+    for (; maxLen != lenLimit; maxLen++)
+      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+        break;
+    distances[offset - 2] = maxLen;
+    if (maxLen == lenLimit)
+    {
+      p->son[p->cyclicBufferPos] = curMatch;
+      MOVE_POS_RET; 
+    }
+  }
+  if (maxLen < 3)
+    maxLen = 3;
+  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+    distances + offset, maxLen) - (distances));
+  MOVE_POS_RET
+}
+
+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 offset;
+  GET_MATCHES_HEADER(3)
+  HASH_ZIP_CALC;
+  curMatch = p->hash[hashValue];
+  p->hash[hashValue] = p->pos;
+  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+    distances, 2) - (distances));
+  MOVE_POS_RET
+}
+
+void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    SKIP_HEADER(2) 
+    HASH2_CALC;
+    curMatch = p->hash[hashValue];
+    p->hash[hashValue] = p->pos;
+    SKIP_FOOTER
+  }
+  while (--num != 0);
+}
+
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    SKIP_HEADER(3)
+    HASH_ZIP_CALC;
+    curMatch = p->hash[hashValue];
+    p->hash[hashValue] = p->pos;
+    SKIP_FOOTER
+  }
+  while (--num != 0);
+}
+
+void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    UInt32 hash2Value;
+    SKIP_HEADER(3)
+    HASH3_CALC;
+    curMatch = p->hash[kFix3HashSize + hashValue];
+    p->hash[hash2Value] =
+    p->hash[kFix3HashSize + hashValue] = p->pos;
+    SKIP_FOOTER
+  }
+  while (--num != 0);
+}
+
+void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    UInt32 hash2Value, hash3Value;
+    SKIP_HEADER(4) 
+    HASH4_CALC;
+    curMatch = p->hash[kFix4HashSize + hashValue];
+    p->hash[                hash2Value] =
+    p->hash[kFix3HashSize + hash3Value] = p->pos;
+    p->hash[kFix4HashSize + hashValue] = p->pos;
+    SKIP_FOOTER
+  }
+  while (--num != 0);
+}
+
+void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    UInt32 hash2Value, hash3Value;
+    SKIP_HEADER(4)
+    HASH4_CALC;
+    curMatch = p->hash[kFix4HashSize + hashValue];
+    p->hash[                hash2Value] =
+    p->hash[kFix3HashSize + hash3Value] =
+    p->hash[kFix4HashSize + hashValue] = p->pos;
+    p->son[p->cyclicBufferPos] = curMatch;
+    MOVE_POS
+  }
+  while (--num != 0);
+}
+
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    SKIP_HEADER(3)
+    HASH_ZIP_CALC;
+    curMatch = p->hash[hashValue];
+    p->hash[hashValue] = p->pos;
+    p->son[p->cyclicBufferPos] = curMatch;
+    MOVE_POS
+  }
+  while (--num != 0);
+}
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
+{
+  vTable->Init = (Mf_Init_Func)MatchFinder_Init;
+  vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
+  vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
+  vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
+  if (!p->btMode)
+  {
+    vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+    vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+  }
+  else if (p->numHashBytes == 2)
+  {
+    vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
+    vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
+  }
+  else if (p->numHashBytes == 3)
+  {
+    vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
+    vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
+  }
+  else
+  {
+    vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
+    vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+  }
+}

+ 106 - 0
lzma/C/Compress/Lz/MatchFinder.h

@@ -0,0 +1,106 @@
+/* MatchFinder.h */
+
+#ifndef __MATCHFINDER_H
+#define __MATCHFINDER_H
+
+#include "../../IStream.h"
+
+typedef UInt32 CLzRef;
+
+typedef struct _CMatchFinder
+{
+  Byte *buffer;
+  UInt32 pos;
+  UInt32 posLimit;
+  UInt32 streamPos;
+  UInt32 lenLimit;
+
+  UInt32 cyclicBufferPos;
+  UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
+
+  UInt32 matchMaxLen;
+  CLzRef *hash;
+  CLzRef *son;
+  UInt32 hashMask;
+  UInt32 cutValue;
+
+  Byte *bufferBase;
+  ISeqInStream *stream;
+  int streamEndWasReached;
+
+  UInt32 blockSize;
+  UInt32 keepSizeBefore;
+  UInt32 keepSizeAfter;
+
+  UInt32 numHashBytes;
+  int directInput;
+  int btMode;
+  /* int skipModeBits; */
+  int bigHash;
+  UInt32 historySize;
+  UInt32 fixedHashSize;
+  UInt32 hashSizeSum;
+  UInt32 numSons;
+
+  HRes result;
+} CMatchFinder;
+
+#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
+#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
+
+#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
+
+int MatchFinder_NeedMove(CMatchFinder *p);
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
+void MatchFinder_MoveBlock(CMatchFinder *p);
+void MatchFinder_ReadIfRequired(CMatchFinder *p);
+
+void MatchFinder_Construct(CMatchFinder *p);
+
+/* Conditions:
+     historySize <= 3 GB
+     keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
+*/
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, 
+    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+    ISzAlloc *alloc);
+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
+
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, 
+    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, 
+    UInt32 *distances, UInt32 maxLen);
+
+/* 
+Conditions:
+  Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
+  Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
+*/
+
+typedef void (*Mf_Init_Func)(void *object);
+typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
+typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
+typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
+typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
+typedef void (*Mf_Skip_Func)(void *object, UInt32);
+
+typedef struct _IMatchFinder
+{
+  Mf_Init_Func Init;
+  Mf_GetIndexByte_Func GetIndexByte;
+  Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
+  Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
+  Mf_GetMatches_Func GetMatches;
+  Mf_Skip_Func Skip;
+} IMatchFinder;
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
+
+void MatchFinder_Init(CMatchFinder *p);
+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+
+#endif

+ 806 - 0
lzma/C/Compress/Lz/MatchFinderMt.c

@@ -0,0 +1,806 @@
+/* MatchFinderMt.c */
+
+#ifdef _WIN32
+#define USE_ALLOCA
+#endif
+
+#ifdef USE_ALLOCA
+#ifdef _WIN32
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+#endif
+
+#include "../../7zCrc.h"
+#include "LzHash.h"
+
+#include "MatchFinderMt.h"
+
+void MtSync_Construct(CMtSync *p)
+{
+  p->wasCreated = False;
+  p->csWasInitialized = False;
+  p->csWasEntered = False;
+  Thread_Construct(&p->thread);
+  Event_Construct(&p->canStart);
+  Event_Construct(&p->wasStarted);
+  Event_Construct(&p->wasStopped);
+  Semaphore_Construct(&p->freeSemaphore);
+  Semaphore_Construct(&p->filledSemaphore);
+}
+
+void MtSync_GetNextBlock(CMtSync *p)
+{
+  if (p->needStart)
+  {
+    p->numProcessedBlocks = 1;
+    p->needStart = False;
+    p->stopWriting = False;
+    p->exit = False;
+    Event_Reset(&p->wasStarted);
+    Event_Reset(&p->wasStopped);
+
+    Event_Set(&p->canStart);
+    Event_Wait(&p->wasStarted);
+  }
+  else
+  {
+    CriticalSection_Leave(&p->cs);
+    p->csWasEntered = False;
+    p->numProcessedBlocks++;
+    Semaphore_Release1(&p->freeSemaphore);
+  }
+  Semaphore_Wait(&p->filledSemaphore);
+  CriticalSection_Enter(&p->cs);
+  p->csWasEntered = True;
+}
+
+/* MtSync_StopWriting must be called if Writing was started */
+
+void MtSync_StopWriting(CMtSync *p)
+{ 
+  UInt32 myNumBlocks = p->numProcessedBlocks;
+  if (!Thread_WasCreated(&p->thread) || p->needStart)
+    return;
+  p->stopWriting = True;
+  if (p->csWasEntered)
+  {
+    CriticalSection_Leave(&p->cs);
+    p->csWasEntered = False;
+  }
+  Semaphore_Release1(&p->freeSemaphore);
+ 
+  Event_Wait(&p->wasStopped);
+
+  while (myNumBlocks++ != p->numProcessedBlocks)
+  {
+    Semaphore_Wait(&p->filledSemaphore);
+    Semaphore_Release1(&p->freeSemaphore);
+  }
+  p->needStart = True;
+}
+
+void MtSync_Destruct(CMtSync *p)
+{
+  if (Thread_WasCreated(&p->thread))
+  {
+    MtSync_StopWriting(p);
+    p->exit = True;
+    if (p->needStart)
+      Event_Set(&p->canStart);
+    Thread_Wait(&p->thread);
+    Thread_Close(&p->thread);
+  }
+  if (p->csWasInitialized)
+  {
+    CriticalSection_Delete(&p->cs);
+    p->csWasInitialized = False;
+  }
+
+  Event_Close(&p->canStart);
+  Event_Close(&p->wasStarted);
+  Event_Close(&p->wasStopped);
+  Semaphore_Close(&p->freeSemaphore);
+  Semaphore_Close(&p->filledSemaphore);
+
+  p->wasCreated = False;
+}
+
+HRes MtSync_Create2(CMtSync *p, unsigned (StdCall *startAddress)(void *), void *obj, UInt32 numBlocks)
+{
+  if (p->wasCreated)
+    return SZ_OK;
+
+  RINOK(CriticalSection_Init(&p->cs));
+  p->csWasInitialized = True;
+
+  RINOK(AutoResetEvent_CreateNotSignaled(&p->canStart));
+  RINOK(AutoResetEvent_CreateNotSignaled(&p->wasStarted));
+  RINOK(AutoResetEvent_CreateNotSignaled(&p->wasStopped));
+  
+  RINOK(Semaphore_Create(&p->freeSemaphore, numBlocks, numBlocks));
+  RINOK(Semaphore_Create(&p->filledSemaphore, 0, numBlocks));
+
+  p->needStart = True;
+  
+  RINOK(Thread_Create(&p->thread, startAddress, obj));
+  p->wasCreated = True;
+  return SZ_OK;
+}
+
+HRes MtSync_Create(CMtSync *p, unsigned (StdCall *startAddress)(void *), void *obj, UInt32 numBlocks)
+{
+  HRes res = MtSync_Create2(p, startAddress, obj, numBlocks);
+  if (res != SZ_OK)
+    MtSync_Destruct(p);
+  return res;
+}
+
+
+void MtSync_Init(CMtSync *p) { p->needStart = True; }
+
+#define kMtMaxValForNormalize 0xFFFFFFFF
+
+#define DEF_GetHeads(name, v) \
+static void GetHeads ## name(const Byte *p, UInt32 pos, \
+UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads) { \
+for (; numHeads != 0; numHeads--) { \
+const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++;  } }
+
+DEF_GetHeads(2,  (p[0] | ((UInt32)p[1] << 8)) & hashMask)
+DEF_GetHeads(3,  (g_CrcTable[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask)
+DEF_GetHeads(4,  (g_CrcTable[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (g_CrcTable[p[3]] << 5)) & hashMask)
+DEF_GetHeads(4b, (g_CrcTable[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask)
+DEF_GetHeads(5,  (g_CrcTable[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (g_CrcTable[p[3]] << 5) ^ (g_CrcTable[p[4]] << 3)) & hashMask)
+
+void HashThreadFunc(CMatchFinderMt *mt)
+{
+  CMtSync *p = &mt->hashSync;
+  for (;;)
+  {
+    UInt32 numProcessedBlocks = 0;
+    Event_Wait(&p->canStart);
+    Event_Set(&p->wasStarted);
+    for (;;)
+    {
+      if (p->exit)
+        return;
+      if (p->stopWriting)
+      {
+        p->numProcessedBlocks = numProcessedBlocks;
+        Event_Set(&p->wasStopped);
+        break;
+      }
+
+      {
+        CMatchFinder *mf = mt->MatchFinder;
+        if (MatchFinder_NeedMove(mf))
+        {
+          CriticalSection_Enter(&mt->btSync.cs);
+          CriticalSection_Enter(&mt->hashSync.cs);
+          {
+            const Byte *beforePtr = MatchFinder_GetPointerToCurrentPos(mf);
+            const Byte *afterPtr;
+            MatchFinder_MoveBlock(mf);
+            afterPtr = MatchFinder_GetPointerToCurrentPos(mf);
+            mt->pointerToCurPos -= beforePtr - afterPtr;
+            mt->buffer -= beforePtr - afterPtr;
+          }
+          CriticalSection_Leave(&mt->btSync.cs);
+          CriticalSection_Leave(&mt->hashSync.cs);
+          continue;
+        }
+
+        Semaphore_Wait(&p->freeSemaphore);
+
+        MatchFinder_ReadIfRequired(mf);
+        if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize))
+        {
+          UInt32 subValue = (mf->pos - mf->historySize - 1);
+          MatchFinder_ReduceOffsets(mf, subValue);
+          MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, mf->hashMask + 1);
+        }
+        {
+          UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize;
+          UInt32 num = mf->streamPos - mf->pos;
+          heads[0] = 2;
+          heads[1] = num;
+          if (num >= mf->numHashBytes)
+          {
+            num = num - mf->numHashBytes + 1;
+            if (num > kMtHashBlockSize - 2)
+              num = kMtHashBlockSize - 2;
+            mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num);
+            heads[0] += num;
+          }
+          mf->pos += num;
+          mf->buffer += num;
+        }
+      }
+
+      Semaphore_Release1(&p->filledSemaphore);
+    }
+  }
+}
+
+void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p)
+{
+  MtSync_GetNextBlock(&p->hashSync);
+  p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize;
+  p->hashBufPosLimit += p->hashBuf[p->hashBufPos++];
+  p->hashNumAvail = p->hashBuf[p->hashBufPos++];
+}
+
+#define kEmptyHashValue 0
+
+/* #define MFMT_GM_INLINE */
+
+#ifdef MFMT_GM_INLINE
+
+#if _MSC_VER >= 1300
+#define NO_INLINE __declspec(noinline) __fastcall 
+#else
+#ifdef _MSC_VER
+#define NO_INLINE __fastcall 
+#endif
+#endif
+
+Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son, 
+    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, 
+    UInt32 *_distances, UInt32 _maxLen, const UInt32 *hash, Int32 limit, UInt32 size, UInt32 *posRes)
+{
+  do
+  {
+  UInt32 *distances = _distances + 1;
+  UInt32 curMatch = pos - *hash++;
+
+  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+  UInt32 len0 = 0, len1 = 0;
+  UInt32 cutValue = _cutValue;
+  UInt32 maxLen = _maxLen;
+  for (;;)
+  {
+    UInt32 delta = pos - curMatch;
+    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+    {
+      *ptr0 = *ptr1 = kEmptyHashValue;
+      break;
+    }
+    {
+      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+      const Byte *pb = cur - delta;
+      UInt32 len = (len0 < len1 ? len0 : len1);
+      if (pb[len] == cur[len])
+      {
+        if (++len != lenLimit && pb[len] == cur[len])
+          while(++len != lenLimit)
+            if (pb[len] != cur[len])
+              break;
+        if (maxLen < len)
+        {
+          *distances++ = maxLen = len;
+          *distances++ = delta - 1;
+          if (len == lenLimit)
+          {
+            *ptr1 = pair[0];
+            *ptr0 = pair[1];
+            break;
+          }
+        }
+      }
+      if (pb[len] < cur[len])
+      {
+        *ptr1 = curMatch;
+        ptr1 = pair + 1;
+        curMatch = *ptr1;
+        len1 = len;
+      }
+      else
+      {
+        *ptr0 = curMatch;
+        ptr0 = pair;
+        curMatch = *ptr0;
+        len0 = len;
+      }
+    }
+  }
+  pos++;
+  _cyclicBufferPos++;
+  cur++;
+  {
+    UInt32 num = (UInt32)(distances - _distances);
+    *_distances = num - 1;
+    _distances += num;
+    limit -= num;
+  }
+  }
+  while (limit > 0 && --size != 0);
+  *posRes = pos;
+  return limit;
+}
+
+#endif
+
+void BtGetMatches(CMatchFinderMt *p, UInt32 *distances)
+{
+  UInt32 numProcessed = 0;
+  UInt32 curPos = 2;
+  UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2);
+  distances[1] = p->hashNumAvail;
+  while (curPos < limit)
+  {
+    if (p->hashBufPos == p->hashBufPosLimit)
+    {
+      MatchFinderMt_GetNextBlock_Hash(p);
+      distances[1] = numProcessed + p->hashNumAvail;
+      if (p->hashNumAvail >= p->numHashBytes)
+        continue;
+      for (; p->hashNumAvail != 0; p->hashNumAvail--)
+        distances[curPos++] = 0;
+      break;
+    }
+    {
+      UInt32 size = p->hashBufPosLimit - p->hashBufPos;
+      UInt32 lenLimit = p->matchMaxLen;
+      UInt32 pos = p->pos;
+      UInt32 cyclicBufferPos = p->cyclicBufferPos;
+      if (lenLimit >= p->hashNumAvail)
+        lenLimit = p->hashNumAvail;
+      {
+        UInt32 size2 = p->hashNumAvail - lenLimit + 1;
+        if (size2 < size)
+          size = size2;
+        size2 = p->cyclicBufferSize - cyclicBufferPos;
+        if (size2 < size)
+          size = size2;
+      }
+      #ifndef MFMT_GM_INLINE
+      while (curPos < limit && size-- != 0)
+      {
+        UInt32 *startDistances = distances + curPos;
+        UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++], 
+          pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, 
+          startDistances + 1, p->numHashBytes - 1) - startDistances);
+        *startDistances = num - 1;
+        curPos += num;
+        cyclicBufferPos++;
+        pos++;
+        p->buffer++;
+      }
+      #else
+      {
+        UInt32 posRes;
+        curPos = limit - GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, 
+          distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos) , size, &posRes);
+        p->hashBufPos += posRes - pos;
+        cyclicBufferPos += posRes - pos;
+        p->buffer += posRes - pos;
+        pos = posRes;
+      }
+      #endif
+
+      numProcessed += pos - p->pos;
+      p->hashNumAvail -= pos - p->pos;
+      p->pos = pos;
+      if (cyclicBufferPos == p->cyclicBufferSize)
+        cyclicBufferPos = 0;
+      p->cyclicBufferPos = cyclicBufferPos;
+    }
+  }
+  distances[0] = curPos;
+}
+
+void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex)
+{
+  CMtSync *sync = &p->hashSync;
+  if (!sync->needStart)
+  {
+    CriticalSection_Enter(&sync->cs);
+    sync->csWasEntered = True;
+  }
+  
+  BtGetMatches(p, p->btBuf + (globalBlockIndex & kMtBtNumBlocksMask) * kMtBtBlockSize);
+
+  if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize)
+  {
+    UInt32 subValue = p->pos - p->cyclicBufferSize;
+    MatchFinder_Normalize3(subValue, p->son, p->cyclicBufferSize * 2);
+    p->pos -= subValue;
+  }
+
+  if (!sync->needStart)
+  {
+    CriticalSection_Leave(&sync->cs);
+    sync->csWasEntered = False;
+  }
+}
+
+void BtThreadFunc(CMatchFinderMt *mt)
+{
+  CMtSync *p = &mt->btSync;
+  for (;;)
+  {
+    UInt32 blockIndex = 0;
+    Event_Wait(&p->canStart);
+    Event_Set(&p->wasStarted);
+    for (;;)
+    {
+      if (p->exit)
+        return;
+      if (p->stopWriting)
+      {
+        p->numProcessedBlocks = blockIndex;
+        MtSync_StopWriting(&mt->hashSync);
+        Event_Set(&p->wasStopped);
+        break;
+      }
+      Semaphore_Wait(&p->freeSemaphore);
+      BtFillBlock(mt, blockIndex++);
+      Semaphore_Release1(&p->filledSemaphore);
+    }
+  }
+}
+
+void MatchFinderMt_Construct(CMatchFinderMt *p)
+{
+  p->hashBuf = 0;
+  MtSync_Construct(&p->hashSync);
+  MtSync_Construct(&p->btSync);
+}
+
+void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc)
+{
+  alloc->Free(p->hashBuf);
+  p->hashBuf = 0;
+}
+
+void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc)
+{
+  MtSync_Destruct(&p->hashSync);
+  MtSync_Destruct(&p->btSync);
+  MatchFinderMt_FreeMem(p, alloc);
+}
+
+#define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks)
+#define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks)
+
+static unsigned StdCall HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p);  return 0; }
+static unsigned StdCall BtThreadFunc2(void *p) 
+{ 
+  #ifdef USE_ALLOCA
+  alloca(0x180);
+  #endif
+  BtThreadFunc((CMatchFinderMt *)p); 
+  return 0; 
+}
+
+HRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, 
+    UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc)
+{ 
+  CMatchFinder *mf = p->MatchFinder;
+  p->historySize = historySize;
+  if (kMtBtBlockSize <= matchMaxLen * 4)
+    return E_INVALIDARG;
+  if (p->hashBuf == 0)
+  {
+    p->hashBuf = (UInt32 *)alloc->Alloc((kHashBufferSize + kBtBufferSize) * sizeof(UInt32));
+    if (p->hashBuf == 0)
+      return SZE_OUTOFMEMORY;
+    p->btBuf = p->hashBuf + kHashBufferSize;
+  }
+  keepAddBufferBefore += (kHashBufferSize + kBtBufferSize);
+  keepAddBufferAfter += kMtHashBlockSize;
+  if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc))
+    return SZE_OUTOFMEMORY;
+
+  RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p, kMtHashNumBlocks));
+  RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p, kMtBtNumBlocks));
+  return SZ_OK;
+}
+
+/* Call it after ReleaseStream / SetStream */
+void MatchFinderMt_Init(CMatchFinderMt *p)
+{ 
+  CMatchFinder *mf = p->MatchFinder;
+  p->btBufPos = p->btBufPosLimit = 0;
+  p->hashBufPos = p->hashBufPosLimit = 0;
+  MatchFinder_Init(mf);
+  p->pointerToCurPos = MatchFinder_GetPointerToCurrentPos(mf);
+  p->btNumAvailBytes = 0;
+  p->lzPos = p->historySize + 1;
+
+  p->hash = mf->hash;
+  p->fixedHashSize = mf->fixedHashSize;
+
+  p->son = mf->son;
+  p->matchMaxLen = mf->matchMaxLen;
+  p->numHashBytes = mf->numHashBytes;
+  p->pos = mf->pos;
+  p->buffer = mf->buffer;
+  p->cyclicBufferPos = mf->cyclicBufferPos;
+  p->cyclicBufferSize = mf->cyclicBufferSize;
+  p->cutValue = mf->cutValue;
+}
+
+/* ReleaseStream is required to finish multithreading */
+void MatchFinderMt_ReleaseStream(CMatchFinderMt *p)
+{ 
+  MtSync_StopWriting(&p->btSync);
+  /* p->MatchFinder->ReleaseStream(); */
+}
+
+void MatchFinderMt_Normalize(CMatchFinderMt *p)
+{
+  MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize);
+  p->lzPos = p->historySize + 1;
+}
+
+void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p)
+{
+  UInt32 blockIndex;
+  MtSync_GetNextBlock(&p->btSync);
+  blockIndex = ((p->btSync.numProcessedBlocks - 1) & kMtBtNumBlocksMask);
+  p->btBufPosLimit = p->btBufPos = blockIndex * kMtBtBlockSize;
+  p->btBufPosLimit += p->btBuf[p->btBufPos++];
+  p->btNumAvailBytes = p->btBuf[p->btBufPos++];
+  if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize) 
+    MatchFinderMt_Normalize(p);
+}
+
+const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p)
+{
+  return p->pointerToCurPos;
+}
+
+#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p);
+
+UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p)
+{ 
+  GET_NEXT_BLOCK_IF_REQUIRED;
+  return p->btNumAvailBytes;
+}
+
+Byte MatchFinderMt_GetIndexByte(CMatchFinderMt *p, Int32 index)
+{ 
+  return p->pointerToCurPos[index]; 
+}
+
+UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+  UInt32 hash2Value, curMatch2;
+  UInt32 *hash = p->hash;
+  const Byte *cur = p->pointerToCurPos;
+  UInt32 lzPos = p->lzPos; 
+  MT_HASH2_CALC
+      
+  curMatch2 = hash[hash2Value];
+  hash[hash2Value] = lzPos;
+
+  if (curMatch2 >= matchMinPos) 
+    if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
+    {
+      *distances++ = 2; 
+      *distances++ = lzPos - curMatch2 - 1;
+    }
+  return distances;
+}
+
+UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+  UInt32 hash2Value, hash3Value, curMatch2, curMatch3;
+  UInt32 *hash = p->hash;
+  const Byte *cur = p->pointerToCurPos;
+  UInt32 lzPos = p->lzPos; 
+  MT_HASH3_CALC
+
+  curMatch2 = hash[                hash2Value];
+  curMatch3 = hash[kFix3HashSize + hash3Value];
+  
+  hash[                hash2Value] = 
+  hash[kFix3HashSize + hash3Value] = 
+    lzPos;
+
+  if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
+  { 
+    distances[1] = lzPos - curMatch2 - 1;
+    if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
+    {
+      distances[0] = 3;
+      return distances + 2;
+    }
+    distances[0] = 2; 
+    distances += 2;
+  }
+  if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
+  { 
+    *distances++ = 3; 
+    *distances++ = lzPos - curMatch3 - 1; 
+  }
+  return distances;
+}
+
+/*
+UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+  UInt32 hash2Value, hash3Value, hash4Value, curMatch2, curMatch3, curMatch4;
+  UInt32 *hash = p->hash;
+  const Byte *cur = p->pointerToCurPos;
+  UInt32 lzPos = p->lzPos; 
+  MT_HASH4_CALC
+      
+  curMatch2 = hash[                hash2Value];
+  curMatch3 = hash[kFix3HashSize + hash3Value];
+  curMatch4 = hash[kFix4HashSize + hash4Value];
+  
+  hash[                hash2Value] = 
+  hash[kFix3HashSize + hash3Value] = 
+  hash[kFix4HashSize + hash4Value] = 
+    lzPos;
+
+  if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
+  {
+    distances[1] = lzPos - curMatch2 - 1;
+    if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
+    {
+      distances[0] =  (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3;
+      return distances + 2;
+    }
+    distances[0] = 2;
+    distances += 2;
+  }
+  if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
+  {
+    distances[1] = lzPos - curMatch3 - 1;
+    if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3])
+    {
+      distances[0] = 4;
+      return distances + 2;
+    }
+    distances[0] = 3;
+    distances += 2;
+  }
+
+  if (curMatch4 >= matchMinPos)
+    if (
+      cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] &&
+      cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3]
+      )
+    {
+      *distances++ = 4;
+      *distances++ = lzPos - curMatch4 - 1;
+    }
+  return distances;
+}
+*/
+
+#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++;
+
+UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances)
+{ 
+  const UInt32 *btBuf = p->btBuf + p->btBufPos;
+  UInt32 len = *btBuf++;
+  p->btBufPos += 1 + len;
+  p->btNumAvailBytes--;
+  {
+    UInt32 i;
+    for (i = 0; i < len; i += 2)
+    {
+      *distances++ = *btBuf++;
+      *distances++ = *btBuf++;
+    }
+  }
+  INCREASE_LZ_POS
+  return len;
+}
+
+UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances)
+{ 
+  const UInt32 *btBuf = p->btBuf + p->btBufPos;
+  UInt32 len = *btBuf++;
+  p->btBufPos += 1 + len;
+
+  if (len == 0)
+  {
+    if (p->btNumAvailBytes-- >= 4) 
+      len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances));
+  }
+  else
+  {
+    /* Condition: there are matches in btBuf with length < p->numHashBytes */
+    UInt32 *distances2;
+    p->btNumAvailBytes--;
+    distances2 = p->MixMatchesFunc(p, p->lzPos - btBuf[1], distances);
+    do 
+    {
+      *distances2++ = *btBuf++;
+      *distances2++ = *btBuf++;
+    }
+    while ((len -= 2) != 0);
+    len  = (UInt32)(distances2 - (distances));
+  }
+  INCREASE_LZ_POS
+  return len;
+}
+
+#define SKIP_HEADER2  do { GET_NEXT_BLOCK_IF_REQUIRED
+#define SKIP_HEADER(n) SKIP_HEADER2 if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash;
+#define SKIP_FOOTER } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while(--num != 0);
+
+void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num)
+{ 
+  SKIP_HEADER2 { p->btNumAvailBytes--;
+  SKIP_FOOTER
+}
+
+void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num)
+{ 
+  SKIP_HEADER(2)
+      UInt32 hash2Value;
+      MT_HASH2_CALC
+      hash[hash2Value] = p->lzPos;
+  SKIP_FOOTER
+}
+
+void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num)
+{ 
+  SKIP_HEADER(3)
+      UInt32 hash2Value, hash3Value;
+      MT_HASH3_CALC
+      hash[kFix3HashSize + hash3Value] = 
+      hash[                hash2Value] = 
+        p->lzPos;
+  SKIP_FOOTER
+}
+
+/*
+void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)
+{ 
+  SKIP_HEADER(4)
+      UInt32 hash2Value, hash3Value, hash4Value;
+      MT_HASH4_CALC
+      hash[kFix4HashSize + hash4Value] = 
+      hash[kFix3HashSize + hash3Value] = 
+      hash[                hash2Value] = 
+        p->lzPos;
+  SKIP_FOOTER
+}
+*/
+
+void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable)
+{
+  vTable->Init = (Mf_Init_Func)MatchFinderMt_Init;
+  vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinderMt_GetIndexByte;
+  vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes;
+  vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos;
+  vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches;
+  switch(p->MatchFinder->numHashBytes)
+  {
+    case 2:
+      p->GetHeadsFunc = GetHeads2;
+      p->MixMatchesFunc = (Mf_Mix_Matches)0;
+      vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip;
+      vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches;
+      break;
+    case 3:
+      p->GetHeadsFunc = GetHeads3;
+      p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2;
+      vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip;
+      break;
+    default:
+    /* case 4: */
+      p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4;
+      /* p->GetHeadsFunc = GetHeads4; */
+      p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3;
+      vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip;
+      break;
+    /*
+    default:
+      p->GetHeadsFunc = GetHeads5;
+      p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4;
+      vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip;
+      break;
+    */
+  }
+}

+ 95 - 0
lzma/C/Compress/Lz/MatchFinderMt.h

@@ -0,0 +1,95 @@
+/* MatchFinderMt.h */
+
+#ifndef __MATCHFINDERMT_H
+#define __MATCHFINDERMT_H
+
+#include "../../Threads.h"
+#include "MatchFinder.h"
+
+#define kMtHashBlockSize (1 << 13)
+#define kMtHashNumBlocks (1 << 3)
+#define kMtHashNumBlocksMask (kMtHashNumBlocks - 1)
+
+#define kMtBtBlockSize (1 << 14)
+#define kMtBtNumBlocks (1 << 6)
+#define kMtBtNumBlocksMask (kMtBtNumBlocks - 1)
+
+typedef struct _CMtSync
+{
+  Bool wasCreated;
+  Bool needStart;
+  Bool exit;
+  Bool stopWriting;
+
+  CThread thread;
+  CAutoResetEvent canStart;
+  CAutoResetEvent wasStarted;
+  CAutoResetEvent wasStopped;
+  CSemaphore freeSemaphore;
+  CSemaphore filledSemaphore;
+  Bool csWasInitialized;
+  Bool csWasEntered;
+  CCriticalSection cs;
+  UInt32 numProcessedBlocks;
+} CMtSync;
+
+typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distances);
+
+/* kMtCacheLineDummy must be >= size_of_CPU_cache_line */
+#define kMtCacheLineDummy 128
+
+typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos,
+  UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads);
+
+typedef struct _CMatchFinderMt
+{
+  /* LZ */
+  const Byte *pointerToCurPos;
+  UInt32 *btBuf;
+  UInt32 btBufPos;
+  UInt32 btBufPosLimit;
+  UInt32 lzPos;
+  UInt32 btNumAvailBytes;
+
+  UInt32 *hash;
+  UInt32 fixedHashSize;
+  UInt32 historySize;
+
+  Mf_Mix_Matches MixMatchesFunc;
+  
+  /* LZ + BT */
+  CMtSync btSync;
+  Byte btDummy[kMtCacheLineDummy];
+
+  /* BT */
+  UInt32 *hashBuf;
+  UInt32 hashBufPos;
+  UInt32 hashBufPosLimit;
+  UInt32 hashNumAvail;
+
+  CLzRef *son;
+  UInt32 matchMaxLen;
+  UInt32 numHashBytes;
+  UInt32 pos;
+  Byte *buffer;
+  UInt32 cyclicBufferPos;
+  UInt32 cyclicBufferSize; /* it must be historySize + 1 */
+  UInt32 cutValue;
+
+  /* BT + Hash */
+  CMtSync hashSync;
+  /* Byte hashDummy[kMtCacheLineDummy]; */
+  
+  /* Hash */
+  Mf_GetHeads GetHeadsFunc;
+  CMatchFinder *MatchFinder;
+} CMatchFinderMt;
+
+void MatchFinderMt_Construct(CMatchFinderMt *p);
+void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc);
+HRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, 
+    UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc);
+void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable);
+void MatchFinderMt_ReleaseStream(CMatchFinderMt *p);
+
+#endif

+ 584 - 0
lzma/C/Compress/Lzma/LzmaDecode.c

@@ -0,0 +1,584 @@
+/*
+  LzmaDecode.c
+  LZMA Decoder (optimized for Speed version)
+  
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this Code, expressly permits you to 
+  statically or dynamically link your Code (or bind by name) to the 
+  interfaces of this file without subjecting your linked Code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaDecode.h"
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
+  { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
+
+#ifdef _LZMA_IN_CB
+
+#define RC_TEST { if (Buffer == BufferLim) \
+  { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \
+  BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }}
+
+#define RC_INIT Buffer = BufferLim = 0; RC_INIT2
+
+#else
+
+#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
+
+#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
+ 
+#endif
+
+#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+
+#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
+  { UpdateBit0(p); mi <<= 1; A0; } else \
+  { UpdateBit1(p); mi = (mi + mi) + 1; A1; } 
+  
+#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)               
+
+#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
+  { int i = numLevels; res = 1; \
+  do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \
+  res -= (1 << numLevels); }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols) 
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+  unsigned char prop0;
+  if (size < LZMA_PROPERTIES_SIZE)
+    return LZMA_RESULT_DATA_ERROR;
+  prop0 = propsData[0];
+  if (prop0 >= (9 * 5 * 5))
+    return LZMA_RESULT_DATA_ERROR;
+  {
+    for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+    for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+    propsRes->lc = prop0;
+    /*
+    unsigned char remainder = (unsigned char)(prop0 / 9);
+    propsRes->lc = prop0 % 9;
+    propsRes->pb = remainder / 5;
+    propsRes->lp = remainder % 5;
+    */
+  }
+
+  #ifdef _LZMA_OUT_READ
+  {
+    int i;
+    propsRes->DictionarySize = 0;
+    for (i = 0; i < 4; i++)
+      propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);
+    if (propsRes->DictionarySize == 0)
+      propsRes->DictionarySize = 1;
+  }
+  #endif
+  return LZMA_RESULT_OK;
+}
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    #ifdef _LZMA_IN_CB
+    ILzmaInCallback *InCallback,
+    #else
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    #endif
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
+{
+  CProb *p = vs->Probs;
+  SizeT nowPos = 0;
+  Byte previousByte = 0;
+  UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+  UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+  int lc = vs->Properties.lc;
+
+  #ifdef _LZMA_OUT_READ
+  
+  UInt32 Range = vs->Range;
+  UInt32 Code = vs->Code;
+  #ifdef _LZMA_IN_CB
+  const Byte *Buffer = vs->Buffer;
+  const Byte *BufferLim = vs->BufferLim;
+  #else
+  const Byte *Buffer = inStream;
+  const Byte *BufferLim = inStream + inSize;
+  #endif
+  int state = vs->State;
+  UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+  int len = vs->RemainLen;
+  UInt32 globalPos = vs->GlobalPos;
+  UInt32 distanceLimit = vs->DistanceLimit;
+
+  Byte *dictionary = vs->Dictionary;
+  UInt32 dictionarySize = vs->Properties.DictionarySize;
+  UInt32 dictionaryPos = vs->DictionaryPos;
+
+  Byte tempDictionary[4];
+
+  #ifndef _LZMA_IN_CB
+  *inSizeProcessed = 0;
+  #endif
+  *outSizeProcessed = 0;
+  if (len == kLzmaStreamWasFinishedId)
+    return LZMA_RESULT_OK;
+
+  if (dictionarySize == 0)
+  {
+    dictionary = tempDictionary;
+    dictionarySize = 1;
+    tempDictionary[0] = vs->TempDictionary[0];
+  }
+
+  if (len == kLzmaNeedInitId)
+  {
+    {
+      UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+      UInt32 i;
+      for (i = 0; i < numProbs; i++)
+        p[i] = kBitModelTotal >> 1; 
+      rep0 = rep1 = rep2 = rep3 = 1;
+      state = 0;
+      globalPos = 0;
+      distanceLimit = 0;
+      dictionaryPos = 0;
+      dictionary[dictionarySize - 1] = 0;
+      #ifdef _LZMA_IN_CB
+      RC_INIT;
+      #else
+      RC_INIT(inStream, inSize);
+      #endif
+    }
+    len = 0;
+  }
+  while(len != 0 && nowPos < outSize)
+  {
+    UInt32 pos = dictionaryPos - rep0;
+    if (pos >= dictionarySize)
+      pos += dictionarySize;
+    outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+    if (++dictionaryPos == dictionarySize)
+      dictionaryPos = 0;
+    len--;
+  }
+  if (dictionaryPos == 0)
+    previousByte = dictionary[dictionarySize - 1];
+  else
+    previousByte = dictionary[dictionaryPos - 1];
+
+  #else /* if !_LZMA_OUT_READ */
+
+  int state = 0;
+  UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+  int len = 0;
+  const Byte *Buffer;
+  const Byte *BufferLim;
+  UInt32 Range;
+  UInt32 Code;
+
+  #ifndef _LZMA_IN_CB
+  *inSizeProcessed = 0;
+  #endif
+  *outSizeProcessed = 0;
+
+  {
+    UInt32 i;
+    UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+    for (i = 0; i < numProbs; i++)
+      p[i] = kBitModelTotal >> 1;
+  }
+  
+  #ifdef _LZMA_IN_CB
+  RC_INIT;
+  #else
+  RC_INIT(inStream, inSize);
+  #endif
+
+  #endif /* _LZMA_OUT_READ */
+
+  while(nowPos < outSize)
+  {
+    CProb *prob;
+    UInt32 bound;
+    int posState = (int)(
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & posStateMask);
+
+    prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+    IfBit0(prob)
+    {
+      int symbol = 1;
+      UpdateBit0(prob)
+      prob = p + Literal + (LZMA_LIT_SIZE * 
+        (((
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+      if (state >= kNumLitStates)
+      {
+        int matchByte;
+        #ifdef _LZMA_OUT_READ
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        matchByte = dictionary[pos];
+        #else
+        matchByte = outStream[nowPos - rep0];
+        #endif
+        do
+        {
+          int bit;
+          CProb *probLit;
+          matchByte <<= 1;
+          bit = (matchByte & 0x100);
+          probLit = prob + 0x100 + bit + symbol;
+          RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
+        }
+        while (symbol < 0x100);
+      }
+      while (symbol < 0x100)
+      {
+        CProb *probLit = prob + symbol;
+        RC_GET_BIT(probLit, symbol)
+      }
+      previousByte = (Byte)symbol;
+
+      outStream[nowPos++] = previousByte;
+      #ifdef _LZMA_OUT_READ
+      if (distanceLimit < dictionarySize)
+        distanceLimit++;
+
+      dictionary[dictionaryPos] = previousByte;
+      if (++dictionaryPos == dictionarySize)
+        dictionaryPos = 0;
+      #endif
+      if (state < 4) state = 0;
+      else if (state < 10) state -= 3;
+      else state -= 6;
+    }
+    else             
+    {
+      UpdateBit1(prob);
+      prob = p + IsRep + state;
+      IfBit0(prob)
+      {
+        UpdateBit0(prob);
+        rep3 = rep2;
+        rep2 = rep1;
+        rep1 = rep0;
+        state = state < kNumLitStates ? 0 : 3;
+        prob = p + LenCoder;
+      }
+      else
+      {
+        UpdateBit1(prob);
+        prob = p + IsRepG0 + state;
+        IfBit0(prob)
+        {
+          UpdateBit0(prob);
+          prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
+          IfBit0(prob)
+          {
+            #ifdef _LZMA_OUT_READ
+            UInt32 pos;
+            #endif
+            UpdateBit0(prob);
+            
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit == 0)
+            #else
+            if (nowPos == 0)
+            #endif
+              return LZMA_RESULT_DATA_ERROR;
+            
+            state = state < kNumLitStates ? 9 : 11;
+            #ifdef _LZMA_OUT_READ
+            pos = dictionaryPos - rep0;
+            if (pos >= dictionarySize)
+              pos += dictionarySize;
+            previousByte = dictionary[pos];
+            dictionary[dictionaryPos] = previousByte;
+            if (++dictionaryPos == dictionarySize)
+              dictionaryPos = 0;
+            #else
+            previousByte = outStream[nowPos - rep0];
+            #endif
+            outStream[nowPos++] = previousByte;
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit < dictionarySize)
+              distanceLimit++;
+            #endif
+
+            continue;
+          }
+          else
+          {
+            UpdateBit1(prob);
+          }
+        }
+        else
+        {
+          UInt32 distance;
+          UpdateBit1(prob);
+          prob = p + IsRepG1 + state;
+          IfBit0(prob)
+          {
+            UpdateBit0(prob);
+            distance = rep1;
+          }
+          else 
+          {
+            UpdateBit1(prob);
+            prob = p + IsRepG2 + state;
+            IfBit0(prob)
+            {
+              UpdateBit0(prob);
+              distance = rep2;
+            }
+            else
+            {
+              UpdateBit1(prob);
+              distance = rep3;
+              rep3 = rep2;
+            }
+            rep2 = rep1;
+          }
+          rep1 = rep0;
+          rep0 = distance;
+        }
+        state = state < kNumLitStates ? 8 : 11;
+        prob = p + RepLenCoder;
+      }
+      {
+        int numBits, offset;
+        CProb *probLen = prob + LenChoice;
+        IfBit0(probLen)
+        {
+          UpdateBit0(probLen);
+          probLen = prob + LenLow + (posState << kLenNumLowBits);
+          offset = 0;
+          numBits = kLenNumLowBits;
+        }
+        else
+        {
+          UpdateBit1(probLen);
+          probLen = prob + LenChoice2;
+          IfBit0(probLen)
+          {
+            UpdateBit0(probLen);
+            probLen = prob + LenMid + (posState << kLenNumMidBits);
+            offset = kLenNumLowSymbols;
+            numBits = kLenNumMidBits;
+          }
+          else
+          {
+            UpdateBit1(probLen);
+            probLen = prob + LenHigh;
+            offset = kLenNumLowSymbols + kLenNumMidSymbols;
+            numBits = kLenNumHighBits;
+          }
+        }
+        RangeDecoderBitTreeDecode(probLen, numBits, len);
+        len += offset;
+      }
+
+      if (state < 4)
+      {
+        int posSlot;
+        state += kNumLitStates;
+        prob = p + PosSlot +
+            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 
+            kNumPosSlotBits);
+        RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
+        if (posSlot >= kStartPosModelIndex)
+        {
+          int numDirectBits = ((posSlot >> 1) - 1);
+          rep0 = (2 | ((UInt32)posSlot & 1));
+          if (posSlot < kEndPosModelIndex)
+          {
+            rep0 <<= numDirectBits;
+            prob = p + SpecPos + rep0 - posSlot - 1;
+          }
+          else
+          {
+            numDirectBits -= kNumAlignBits;
+            do
+            {
+              RC_NORMALIZE
+              Range >>= 1;
+              rep0 <<= 1;
+              if (Code >= Range)
+              {
+                Code -= Range;
+                rep0 |= 1;
+              }
+            }
+            while (--numDirectBits != 0);
+            prob = p + Align;
+            rep0 <<= kNumAlignBits;
+            numDirectBits = kNumAlignBits;
+          }
+          {
+            int i = 1;
+            int mi = 1;
+            do
+            {
+              CProb *prob3 = prob + mi;
+              RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
+              i <<= 1;
+            }
+            while(--numDirectBits != 0);
+          }
+        }
+        else
+          rep0 = posSlot;
+        if (++rep0 == (UInt32)(0))
+        {
+          /* it's for stream version */
+          len = kLzmaStreamWasFinishedId;
+          break;
+        }
+      }
+
+      len += kMatchMinLen;
+      #ifdef _LZMA_OUT_READ
+      if (rep0 > distanceLimit) 
+      #else
+      if (rep0 > nowPos)
+      #endif
+        return LZMA_RESULT_DATA_ERROR;
+
+      #ifdef _LZMA_OUT_READ
+      if (dictionarySize - distanceLimit > (UInt32)len)
+        distanceLimit += len;
+      else
+        distanceLimit = dictionarySize;
+      #endif
+
+      do
+      {
+        #ifdef _LZMA_OUT_READ
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        previousByte = dictionary[pos];
+        dictionary[dictionaryPos] = previousByte;
+        if (++dictionaryPos == dictionarySize)
+          dictionaryPos = 0;
+        #else
+        previousByte = outStream[nowPos - rep0];
+        #endif
+        len--;
+        outStream[nowPos++] = previousByte;
+      }
+      while(len != 0 && nowPos < outSize);
+    }
+  }
+  RC_NORMALIZE;
+
+  #ifdef _LZMA_OUT_READ
+  vs->Range = Range;
+  vs->Code = Code;
+  vs->DictionaryPos = dictionaryPos;
+  vs->GlobalPos = globalPos + (UInt32)nowPos;
+  vs->DistanceLimit = distanceLimit;
+  vs->Reps[0] = rep0;
+  vs->Reps[1] = rep1;
+  vs->Reps[2] = rep2;
+  vs->Reps[3] = rep3;
+  vs->State = state;
+  vs->RemainLen = len;
+  vs->TempDictionary[0] = tempDictionary[0];
+  #endif
+
+  #ifdef _LZMA_IN_CB
+  vs->Buffer = Buffer;
+  vs->BufferLim = BufferLim;
+  #else
+  *inSizeProcessed = (SizeT)(Buffer - inStream);
+  #endif
+  *outSizeProcessed = nowPos;
+  return LZMA_RESULT_OK;
+}

+ 113 - 0
lzma/C/Compress/Lzma/LzmaDecode.h

@@ -0,0 +1,113 @@
+/* 
+  LzmaDecode.h
+  LZMA Decoder interface
+
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this code, expressly permits you to 
+  statically or dynamically link your code (or bind by name) to the 
+  interfaces of this file without subjecting your linked code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+#include "LzmaTypes.h"
+
+/* #define _LZMA_IN_CB */
+/* Use callback for input data */
+
+/* #define _LZMA_OUT_READ */
+/* Use read function for output data */
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs, 
+   but memory usage will be doubled in that case */
+
+/* #define _LZMA_LOC_OPT */
+/* Enable local speed optimizations inside code */
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb UInt16
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+#ifdef _LZMA_IN_CB
+typedef struct _ILzmaInCallback
+{
+  int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize);
+} ILzmaInCallback;
+#endif
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+  int lc;
+  int lp;
+  int pb;
+  #ifdef _LZMA_OUT_READ
+  UInt32 DictionarySize;
+  #endif
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp)))
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+  CLzmaProperties Properties;
+  CProb *Probs;
+
+  #ifdef _LZMA_IN_CB
+  const unsigned char *Buffer;
+  const unsigned char *BufferLim;
+  #endif
+
+  #ifdef _LZMA_OUT_READ
+  unsigned char *Dictionary;
+  UInt32 Range;
+  UInt32 Code;
+  UInt32 DictionaryPos;
+  UInt32 GlobalPos;
+  UInt32 DistanceLimit;
+  UInt32 Reps[4];
+  int State;
+  int RemainLen;
+  unsigned char TempDictionary[4];
+  #endif
+} CLzmaDecoderState;
+
+#ifdef _LZMA_OUT_READ
+#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; }
+#endif
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    #ifdef _LZMA_IN_CB
+    ILzmaInCallback *inCallback,
+    #else
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    #endif
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed);
+
+#endif

+ 712 - 0
lzma/C/Compress/Lzma/LzmaDecodeSize.c

@@ -0,0 +1,712 @@
+/*
+  LzmaDecodeSize.c
+  LZMA Decoder (optimized for Size version)
+  
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this code, expressly permits you to 
+  statically or dynamically link your code (or bind by name) to the 
+  interfaces of this file without subjecting your linked code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaDecode.h"
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+typedef struct _CRangeDecoder
+{
+  const Byte *Buffer;
+  const Byte *BufferLim;
+  UInt32 Range;
+  UInt32 Code;
+  #ifdef _LZMA_IN_CB
+  ILzmaInCallback *InCallback;
+  int Result;
+  #endif
+  int ExtraBytes;
+} CRangeDecoder;
+
+Byte RangeDecoderReadByte(CRangeDecoder *rd)
+{
+  if (rd->Buffer == rd->BufferLim)
+  {
+    #ifdef _LZMA_IN_CB
+    SizeT size;
+    rd->Result = rd->InCallback->Read(rd->InCallback, &rd->Buffer, &size);
+    rd->BufferLim = rd->Buffer + size;
+    if (size == 0)
+    #endif
+    {
+      rd->ExtraBytes = 1;
+      return 0xFF;
+    }
+  }
+  return (*rd->Buffer++);
+}
+
+/* #define ReadByte (*rd->Buffer++) */
+#define ReadByte (RangeDecoderReadByte(rd))
+
+void RangeDecoderInit(CRangeDecoder *rd
+  #ifndef _LZMA_IN_CB
+    , const Byte *stream, SizeT bufferSize
+  #endif
+    )
+{
+  int i;
+  #ifdef _LZMA_IN_CB
+  rd->Buffer = rd->BufferLim = 0;
+  #else
+  rd->Buffer = stream;
+  rd->BufferLim = stream + bufferSize;
+  #endif
+  rd->ExtraBytes = 0;
+  rd->Code = 0;
+  rd->Range = (0xFFFFFFFF);
+  for(i = 0; i < 5; i++)
+    rd->Code = (rd->Code << 8) | ReadByte;
+}
+
+#define RC_INIT_VAR UInt32 range = rd->Range; UInt32 code = rd->Code;        
+#define RC_FLUSH_VAR rd->Range = range; rd->Code = code;
+#define RC_NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | ReadByte; }
+
+UInt32 RangeDecoderDecodeDirectBits(CRangeDecoder *rd, int numTotalBits)
+{
+  RC_INIT_VAR
+  UInt32 result = 0;
+  int i;
+  for (i = numTotalBits; i != 0; i--)
+  {
+    /* UInt32 t; */
+    range >>= 1;
+
+    result <<= 1;
+    if (code >= range)
+    {
+      code -= range;
+      result |= 1;
+    }
+    /*
+    t = (code - range) >> 31;
+    t &= 1;
+    code -= range & (t - 1);
+    result = (result + result) | (1 - t);
+    */
+    RC_NORMALIZE
+  }
+  RC_FLUSH_VAR
+  return result;
+}
+
+int RangeDecoderBitDecode(CProb *prob, CRangeDecoder *rd)
+{
+  UInt32 bound = (rd->Range >> kNumBitModelTotalBits) * *prob;
+  if (rd->Code < bound)
+  {
+    rd->Range = bound;
+    *prob += (kBitModelTotal - *prob) >> kNumMoveBits;
+    if (rd->Range < kTopValue)
+    {
+      rd->Code = (rd->Code << 8) | ReadByte;
+      rd->Range <<= 8;
+    }
+    return 0;
+  }
+  else
+  {
+    rd->Range -= bound;
+    rd->Code -= bound;
+    *prob -= (*prob) >> kNumMoveBits;
+    if (rd->Range < kTopValue)
+    {
+      rd->Code = (rd->Code << 8) | ReadByte;
+      rd->Range <<= 8;
+    }
+    return 1;
+  }
+}
+
+#define RC_GET_BIT2(prob, mi, A0, A1) \
+  UInt32 bound = (range >> kNumBitModelTotalBits) * *prob; \
+  if (code < bound) \
+    { A0; range = bound; *prob += (kBitModelTotal - *prob) >> kNumMoveBits; mi <<= 1; } \
+  else \
+    { A1; range -= bound; code -= bound; *prob -= (*prob) >> kNumMoveBits; mi = (mi + mi) + 1; } \
+  RC_NORMALIZE
+
+#define RC_GET_BIT(prob, mi) RC_GET_BIT2(prob, mi, ; , ;)               
+
+int RangeDecoderBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
+{
+  int mi = 1;
+  int i;
+  #ifdef _LZMA_LOC_OPT
+  RC_INIT_VAR
+  #endif
+  for(i = numLevels; i != 0; i--)
+  {
+    #ifdef _LZMA_LOC_OPT
+    CProb *prob = probs + mi;
+    RC_GET_BIT(prob, mi)
+    #else
+    mi = (mi + mi) + RangeDecoderBitDecode(probs + mi, rd);
+    #endif
+  }
+  #ifdef _LZMA_LOC_OPT
+  RC_FLUSH_VAR
+  #endif
+  return mi - (1 << numLevels);
+}
+
+int RangeDecoderReverseBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
+{
+  int mi = 1;
+  int i;
+  int symbol = 0;
+  #ifdef _LZMA_LOC_OPT
+  RC_INIT_VAR
+  #endif
+  for(i = 0; i < numLevels; i++)
+  {
+    #ifdef _LZMA_LOC_OPT
+    CProb *prob = probs + mi;
+    RC_GET_BIT2(prob, mi, ; , symbol |= (1 << i))
+    #else
+    int bit = RangeDecoderBitDecode(probs + mi, rd);
+    mi = mi + mi + bit;
+    symbol |= (bit << i);
+    #endif
+  }
+  #ifdef _LZMA_LOC_OPT
+  RC_FLUSH_VAR
+  #endif
+  return symbol;
+}
+
+Byte LzmaLiteralDecode(CProb *probs, CRangeDecoder *rd)
+{ 
+  int symbol = 1;
+  #ifdef _LZMA_LOC_OPT
+  RC_INIT_VAR
+  #endif
+  do
+  {
+    #ifdef _LZMA_LOC_OPT
+    CProb *prob = probs + symbol;
+    RC_GET_BIT(prob, symbol)
+    #else
+    symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
+    #endif
+  }
+  while (symbol < 0x100);
+  #ifdef _LZMA_LOC_OPT
+  RC_FLUSH_VAR
+  #endif
+  return symbol;
+}
+
+Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte)
+{ 
+  int symbol = 1;
+  #ifdef _LZMA_LOC_OPT
+  RC_INIT_VAR
+  #endif
+  do
+  {
+    int bit;
+    int matchBit = (matchByte >> 7) & 1;
+    matchByte <<= 1;
+    #ifdef _LZMA_LOC_OPT
+    {
+      CProb *prob = probs + 0x100 + (matchBit << 8) + symbol;
+      RC_GET_BIT2(prob, symbol, bit = 0, bit = 1)
+    }
+    #else
+    bit = RangeDecoderBitDecode(probs + 0x100 + (matchBit << 8) + symbol, rd);
+    symbol = (symbol << 1) | bit;
+    #endif
+    if (matchBit != bit)
+    {
+      while (symbol < 0x100)
+      {
+        #ifdef _LZMA_LOC_OPT
+        CProb *prob = probs + symbol;
+        RC_GET_BIT(prob, symbol)
+        #else
+        symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
+        #endif
+      }
+      break;
+    }
+  }
+  while (symbol < 0x100);
+  #ifdef _LZMA_LOC_OPT
+  RC_FLUSH_VAR
+  #endif
+  return symbol;
+}
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols) 
+
+int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState)
+{
+  if(RangeDecoderBitDecode(p + LenChoice, rd) == 0)
+    return RangeDecoderBitTreeDecode(p + LenLow +
+        (posState << kLenNumLowBits), kLenNumLowBits, rd);
+  if(RangeDecoderBitDecode(p + LenChoice2, rd) == 0)
+    return kLenNumLowSymbols + RangeDecoderBitTreeDecode(p + LenMid +
+        (posState << kLenNumMidBits), kLenNumMidBits, rd);
+  return kLenNumLowSymbols + kLenNumMidSymbols + 
+      RangeDecoderBitTreeDecode(p + LenHigh, kLenNumHighBits, rd);
+}
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+  unsigned char prop0;
+  if (size < LZMA_PROPERTIES_SIZE)
+    return LZMA_RESULT_DATA_ERROR;
+  prop0 = propsData[0];
+  if (prop0 >= (9 * 5 * 5))
+    return LZMA_RESULT_DATA_ERROR;
+  {
+    for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+    for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+    propsRes->lc = prop0;
+    /*
+    unsigned char remainder = (unsigned char)(prop0 / 9);
+    propsRes->lc = prop0 % 9;
+    propsRes->pb = remainder / 5;
+    propsRes->lp = remainder % 5;
+    */
+  }
+
+  #ifdef _LZMA_OUT_READ
+  {
+    int i;
+    propsRes->DictionarySize = 0;
+    for (i = 0; i < 4; i++)
+      propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);
+    if (propsRes->DictionarySize == 0)
+      propsRes->DictionarySize = 1;
+  }
+  #endif
+  return LZMA_RESULT_OK;
+}
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    #ifdef _LZMA_IN_CB
+    ILzmaInCallback *InCallback,
+    #else
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    #endif
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
+{
+  CProb *p = vs->Probs;
+  SizeT nowPos = 0;
+  Byte previousByte = 0;
+  UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+  UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+  int lc = vs->Properties.lc;
+  CRangeDecoder rd;
+
+  #ifdef _LZMA_OUT_READ
+  
+  int state = vs->State;
+  UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+  int len = vs->RemainLen;
+  UInt32 globalPos = vs->GlobalPos;
+  UInt32 distanceLimit = vs->DistanceLimit;
+
+  Byte *dictionary = vs->Dictionary;
+  UInt32 dictionarySize = vs->Properties.DictionarySize;
+  UInt32 dictionaryPos = vs->DictionaryPos;
+
+  Byte tempDictionary[4];
+
+  rd.Range = vs->Range;
+  rd.Code = vs->Code;
+  #ifdef _LZMA_IN_CB
+  rd.InCallback = InCallback;
+  rd.Buffer = vs->Buffer;
+  rd.BufferLim = vs->BufferLim;
+  #else
+  rd.Buffer = inStream;
+  rd.BufferLim = inStream + inSize;
+  #endif
+
+  #ifndef _LZMA_IN_CB
+  *inSizeProcessed = 0;
+  #endif
+  *outSizeProcessed = 0;
+  if (len == kLzmaStreamWasFinishedId)
+    return LZMA_RESULT_OK;
+
+  if (dictionarySize == 0)
+  {
+    dictionary = tempDictionary;
+    dictionarySize = 1;
+    tempDictionary[0] = vs->TempDictionary[0];
+  }
+
+  if (len == kLzmaNeedInitId)
+  {
+    {
+      UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+      UInt32 i;
+      for (i = 0; i < numProbs; i++)
+        p[i] = kBitModelTotal >> 1; 
+      rep0 = rep1 = rep2 = rep3 = 1;
+      state = 0;
+      globalPos = 0;
+      distanceLimit = 0;
+      dictionaryPos = 0;
+      dictionary[dictionarySize - 1] = 0;
+      RangeDecoderInit(&rd
+          #ifndef _LZMA_IN_CB
+          , inStream, inSize
+          #endif
+          );
+      #ifdef _LZMA_IN_CB
+      if (rd.Result != LZMA_RESULT_OK)
+        return rd.Result;
+      #endif
+      if (rd.ExtraBytes != 0)
+        return LZMA_RESULT_DATA_ERROR;
+    }
+    len = 0;
+  }
+  while(len != 0 && nowPos < outSize)
+  {
+    UInt32 pos = dictionaryPos - rep0;
+    if (pos >= dictionarySize)
+      pos += dictionarySize;
+    outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+    if (++dictionaryPos == dictionarySize)
+      dictionaryPos = 0;
+    len--;
+  }
+  if (dictionaryPos == 0)
+    previousByte = dictionary[dictionarySize - 1];
+  else
+    previousByte = dictionary[dictionaryPos - 1];
+
+  #ifdef _LZMA_IN_CB
+  rd.Result = LZMA_RESULT_OK;
+  #endif
+  rd.ExtraBytes = 0;
+
+  #else /* if !_LZMA_OUT_READ */
+
+  int state = 0;
+  UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+  int len = 0;
+
+  #ifndef _LZMA_IN_CB
+  *inSizeProcessed = 0;
+  #endif
+  *outSizeProcessed = 0;
+
+  {
+    UInt32 i;
+    UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+    for (i = 0; i < numProbs; i++)
+      p[i] = kBitModelTotal >> 1;
+  }
+  
+  #ifdef _LZMA_IN_CB
+  rd.InCallback = InCallback;
+  #endif
+  RangeDecoderInit(&rd
+      #ifndef _LZMA_IN_CB
+      , inStream, inSize
+      #endif
+      );
+
+  #ifdef _LZMA_IN_CB
+  if (rd.Result != LZMA_RESULT_OK)
+    return rd.Result;
+  #endif
+  if (rd.ExtraBytes != 0)
+    return LZMA_RESULT_DATA_ERROR;
+
+  #endif /* _LZMA_OUT_READ */
+
+
+  while(nowPos < outSize)
+  {
+    int posState = (int)(
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & posStateMask);
+    #ifdef _LZMA_IN_CB
+    if (rd.Result != LZMA_RESULT_OK)
+      return rd.Result;
+    #endif
+    if (rd.ExtraBytes != 0)
+      return LZMA_RESULT_DATA_ERROR;
+    if (RangeDecoderBitDecode(p + IsMatch + (state << kNumPosBitsMax) + posState, &rd) == 0)
+    {
+      CProb *probs = p + Literal + (LZMA_LIT_SIZE * 
+        (((
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+      if (state >= kNumLitStates)
+      {
+        Byte matchByte;
+        #ifdef _LZMA_OUT_READ
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        matchByte = dictionary[pos];
+        #else
+        matchByte = outStream[nowPos - rep0];
+        #endif
+        previousByte = LzmaLiteralDecodeMatch(probs, &rd, matchByte);
+      }
+      else
+        previousByte = LzmaLiteralDecode(probs, &rd);
+      outStream[nowPos++] = previousByte;
+      #ifdef _LZMA_OUT_READ
+      if (distanceLimit < dictionarySize)
+        distanceLimit++;
+
+      dictionary[dictionaryPos] = previousByte;
+      if (++dictionaryPos == dictionarySize)
+        dictionaryPos = 0;
+      #endif
+      if (state < 4) state = 0;
+      else if (state < 10) state -= 3;
+      else state -= 6;
+    }
+    else             
+    {
+      if (RangeDecoderBitDecode(p + IsRep + state, &rd) == 1)
+      {
+        if (RangeDecoderBitDecode(p + IsRepG0 + state, &rd) == 0)
+        {
+          if (RangeDecoderBitDecode(p + IsRep0Long + (state << kNumPosBitsMax) + posState, &rd) == 0)
+          {
+            #ifdef _LZMA_OUT_READ
+            UInt32 pos;
+            #endif
+      
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit == 0)
+            #else
+            if (nowPos == 0)
+            #endif
+              return LZMA_RESULT_DATA_ERROR;
+
+            state = state < 7 ? 9 : 11;
+            #ifdef _LZMA_OUT_READ
+            pos = dictionaryPos - rep0;
+            if (pos >= dictionarySize)
+              pos += dictionarySize;
+            previousByte = dictionary[pos];
+            dictionary[dictionaryPos] = previousByte;
+            if (++dictionaryPos == dictionarySize)
+              dictionaryPos = 0;
+            #else
+            previousByte = outStream[nowPos - rep0];
+            #endif
+            outStream[nowPos++] = previousByte;
+
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit < dictionarySize)
+              distanceLimit++;
+            #endif
+            continue;
+          }
+        }
+        else
+        {
+          UInt32 distance;
+          if(RangeDecoderBitDecode(p + IsRepG1 + state, &rd) == 0)
+            distance = rep1;
+          else 
+          {
+            if(RangeDecoderBitDecode(p + IsRepG2 + state, &rd) == 0)
+              distance = rep2;
+            else
+            {
+              distance = rep3;
+              rep3 = rep2;
+            }
+            rep2 = rep1;
+          }
+          rep1 = rep0;
+          rep0 = distance;
+        }
+        len = LzmaLenDecode(p + RepLenCoder, &rd, posState);
+        state = state < 7 ? 8 : 11;
+      }
+      else
+      {
+        int posSlot;
+        rep3 = rep2;
+        rep2 = rep1;
+        rep1 = rep0;
+        state = state < 7 ? 7 : 10;
+        len = LzmaLenDecode(p + LenCoder, &rd, posState);
+        posSlot = RangeDecoderBitTreeDecode(p + PosSlot +
+            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 
+            kNumPosSlotBits), kNumPosSlotBits, &rd);
+        if (posSlot >= kStartPosModelIndex)
+        {
+          int numDirectBits = ((posSlot >> 1) - 1);
+          rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits);
+          if (posSlot < kEndPosModelIndex)
+          {
+            rep0 += RangeDecoderReverseBitTreeDecode(
+                p + SpecPos + rep0 - posSlot - 1, numDirectBits, &rd);
+          }
+          else
+          {
+            rep0 += RangeDecoderDecodeDirectBits(&rd, 
+                numDirectBits - kNumAlignBits) << kNumAlignBits;
+            rep0 += RangeDecoderReverseBitTreeDecode(p + Align, kNumAlignBits, &rd);
+          }
+        }
+        else
+          rep0 = posSlot;
+        if (++rep0 == (UInt32)(0))
+        {
+          /* it's for stream version */
+          len = kLzmaStreamWasFinishedId;
+          break;
+        }
+      }
+
+      len += kMatchMinLen;
+      #ifdef _LZMA_OUT_READ
+      if (rep0 > distanceLimit) 
+      #else
+      if (rep0 > nowPos)
+      #endif
+        return LZMA_RESULT_DATA_ERROR;
+
+      #ifdef _LZMA_OUT_READ
+      if (dictionarySize - distanceLimit > (UInt32)len)
+        distanceLimit += len;
+      else
+        distanceLimit = dictionarySize;
+      #endif
+
+      do
+      {
+        #ifdef _LZMA_OUT_READ
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        previousByte = dictionary[pos];
+        dictionary[dictionaryPos] = previousByte;
+        if (++dictionaryPos == dictionarySize)
+          dictionaryPos = 0;
+        #else
+        previousByte = outStream[nowPos - rep0];
+        #endif
+        len--;
+        outStream[nowPos++] = previousByte;
+      }
+      while(len != 0 && nowPos < outSize);
+    }
+  }
+
+
+  #ifdef _LZMA_OUT_READ
+  vs->Range = rd.Range;
+  vs->Code = rd.Code;
+  vs->DictionaryPos = dictionaryPos;
+  vs->GlobalPos = globalPos + (UInt32)nowPos;
+  vs->DistanceLimit = distanceLimit;
+  vs->Reps[0] = rep0;
+  vs->Reps[1] = rep1;
+  vs->Reps[2] = rep2;
+  vs->Reps[3] = rep3;
+  vs->State = state;
+  vs->RemainLen = len;
+  vs->TempDictionary[0] = tempDictionary[0];
+  #endif
+
+  #ifdef _LZMA_IN_CB
+  vs->Buffer = rd.Buffer;
+  vs->BufferLim = rd.BufferLim;
+  #else
+  *inSizeProcessed = (SizeT)(rd.Buffer - inStream);
+  #endif
+  *outSizeProcessed = nowPos;
+  return LZMA_RESULT_OK;
+}

+ 521 - 0
lzma/C/Compress/Lzma/LzmaStateDecode.c

@@ -0,0 +1,521 @@
+/*
+  LzmaStateDecode.c
+  LZMA Decoder (State version)
+  
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this Code, expressly permits you to 
+  statically or dynamically link your Code (or bind by name) to the 
+  interfaces of this file without subjecting your linked Code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaStateDecode.h"
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT Code = 0; Range = 0xFFFFFFFF; \
+  { int i; for(i = 0; i < 5; i++) { Code = (Code << 8) | RC_READ_BYTE; }}
+
+#define RC_NORMALIZE if (Range < kTopValue) { Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+
+#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
+  { UpdateBit0(p); mi <<= 1; A0; } else \
+  { UpdateBit1(p); mi = (mi + mi) + 1; A1; } 
+  
+#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)               
+
+#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
+  { int i = numLevels; res = 1; \
+  do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \
+  res -= (1 << numLevels); }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols) 
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+/* kRequiredInBufferSize = number of required input bytes for worst case: 
+   longest match with longest distance.
+   kLzmaInBufferSize must be larger than kRequiredInBufferSize 
+   23 bits = 2 (match select) + 10 (len) + 6 (distance) + 4(align) + 1 (RC_NORMALIZE)
+*/
+
+#define kRequiredInBufferSize ((23 * (kNumBitModelTotalBits - kNumMoveBits + 1) + 26 + 9) / 8)
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+  unsigned char prop0;
+  if (size < LZMA_PROPERTIES_SIZE)
+    return LZMA_RESULT_DATA_ERROR;
+  prop0 = propsData[0];
+  if (prop0 >= (9 * 5 * 5))
+    return LZMA_RESULT_DATA_ERROR;
+  {
+    for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+    for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+    propsRes->lc = prop0;
+    /*
+    unsigned char remainder = (unsigned char)(prop0 / 9);
+    propsRes->lc = prop0 % 9;
+    propsRes->pb = remainder / 5;
+    propsRes->lp = remainder % 5;
+    */
+  }
+
+  {
+    int i;
+    propsRes->DictionarySize = 0;
+    for (i = 0; i < 4; i++)
+      propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);
+    if (propsRes->DictionarySize == 0)
+      propsRes->DictionarySize = 1;
+    return LZMA_RESULT_OK;
+  }
+}
+
+int LzmaDecode(
+    CLzmaDecoderState *vs,
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed,
+    int finishDecoding)
+{
+  UInt32 Range = vs->Range;
+  UInt32 Code = vs->Code;
+
+  unsigned char *Buffer = vs->Buffer;
+  int BufferSize = vs->BufferSize; /* don't change it to unsigned int */
+  CProb *p = vs->Probs;
+
+  int state = vs->State;
+  unsigned char previousByte;
+  UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+  SizeT nowPos = 0;
+  UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+  UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+  int lc = vs->Properties.lc;
+  int len = vs->RemainLen;
+  UInt32 globalPos = vs->GlobalPos;
+  UInt32 distanceLimit = vs->DistanceLimit;
+
+  unsigned char *dictionary = vs->Dictionary;
+  UInt32 dictionarySize = vs->Properties.DictionarySize;
+  UInt32 dictionaryPos = vs->DictionaryPos;
+
+  unsigned char tempDictionary[4];
+
+  (*inSizeProcessed) = 0;
+  (*outSizeProcessed) = 0;
+  if (len == kLzmaStreamWasFinishedId)
+    return LZMA_RESULT_OK;
+
+  if (dictionarySize == 0)
+  {
+    dictionary = tempDictionary;
+    dictionarySize = 1;
+    tempDictionary[0] = vs->TempDictionary[0];
+  }
+
+  if (len == kLzmaNeedInitId)
+  {
+    while (inSize > 0 && BufferSize < kLzmaInBufferSize)
+    {
+      Buffer[BufferSize++] = *inStream++;
+      (*inSizeProcessed)++;
+      inSize--;
+    }
+    if (BufferSize < 5)
+    {
+      vs->BufferSize = BufferSize;
+      return finishDecoding ? LZMA_RESULT_DATA_ERROR : LZMA_RESULT_OK;
+    }
+    {
+      UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+      UInt32 i;
+      for (i = 0; i < numProbs; i++)
+        p[i] = kBitModelTotal >> 1; 
+      rep0 = rep1 = rep2 = rep3 = 1;
+      state = 0;
+      globalPos = 0;
+      distanceLimit = 0;
+      dictionaryPos = 0;
+      dictionary[dictionarySize - 1] = 0;
+      RC_INIT;
+    }
+    len = 0;
+  }
+  while(len != 0 && nowPos < outSize)
+  {
+    UInt32 pos = dictionaryPos - rep0;
+    if (pos >= dictionarySize)
+      pos += dictionarySize;
+    outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+    if (++dictionaryPos == dictionarySize)
+      dictionaryPos = 0;
+    len--;
+  }
+  if (dictionaryPos == 0)
+    previousByte = dictionary[dictionarySize - 1];
+  else
+    previousByte = dictionary[dictionaryPos - 1];
+
+  for (;;)
+  {
+    int bufferPos = (int)(Buffer - vs->Buffer);
+    if (BufferSize - bufferPos < kRequiredInBufferSize)
+    {
+      int i;
+      BufferSize -= bufferPos;
+      if (BufferSize < 0)
+        return LZMA_RESULT_DATA_ERROR;
+      for (i = 0; i < BufferSize; i++)
+        vs->Buffer[i] = Buffer[i];
+      Buffer = vs->Buffer;
+      while (inSize > 0 && BufferSize < kLzmaInBufferSize)
+      {
+        Buffer[BufferSize++] = *inStream++;
+        (*inSizeProcessed)++;
+        inSize--;
+      }
+      if (BufferSize < kRequiredInBufferSize && !finishDecoding)
+        break;
+    }
+    if (nowPos >= outSize)
+      break;
+    {
+    CProb *prob;
+    UInt32 bound;
+    int posState = (int)((nowPos + globalPos) & posStateMask);
+
+    prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+    IfBit0(prob)
+    {
+      int symbol = 1;
+      UpdateBit0(prob)
+      prob = p + Literal + (LZMA_LIT_SIZE * 
+        ((((nowPos + globalPos)& literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+      if (state >= kNumLitStates)
+      {
+        int matchByte;
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        matchByte = dictionary[pos];
+        do
+        {
+          int bit;
+          CProb *probLit;
+          matchByte <<= 1;
+          bit = (matchByte & 0x100);
+          probLit = prob + 0x100 + bit + symbol;
+          RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
+        }
+        while (symbol < 0x100);
+      }
+      while (symbol < 0x100)
+      {
+        CProb *probLit = prob + symbol;
+        RC_GET_BIT(probLit, symbol)
+      }
+      previousByte = (unsigned char)symbol;
+
+      outStream[nowPos++] = previousByte;
+      if (distanceLimit < dictionarySize)
+        distanceLimit++;
+
+      dictionary[dictionaryPos] = previousByte;
+      if (++dictionaryPos == dictionarySize)
+        dictionaryPos = 0;
+      if (state < 4) state = 0;
+      else if (state < 10) state -= 3;
+      else state -= 6;
+    }
+    else             
+    {
+      UpdateBit1(prob);
+      prob = p + IsRep + state;
+      IfBit0(prob)
+      {
+        UpdateBit0(prob);
+        rep3 = rep2;
+        rep2 = rep1;
+        rep1 = rep0;
+        state = state < kNumLitStates ? 0 : 3;
+        prob = p + LenCoder;
+      }
+      else
+      {
+        UpdateBit1(prob);
+        prob = p + IsRepG0 + state;
+        IfBit0(prob)
+        {
+          UpdateBit0(prob);
+          prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
+          IfBit0(prob)
+          {
+            UInt32 pos;
+            UpdateBit0(prob);
+            if (distanceLimit == 0)
+              return LZMA_RESULT_DATA_ERROR;
+            if (distanceLimit < dictionarySize)
+              distanceLimit++;
+            state = state < kNumLitStates ? 9 : 11;
+            pos = dictionaryPos - rep0;
+            if (pos >= dictionarySize)
+              pos += dictionarySize;
+            previousByte = dictionary[pos];
+            dictionary[dictionaryPos] = previousByte;
+            if (++dictionaryPos == dictionarySize)
+              dictionaryPos = 0;
+            outStream[nowPos++] = previousByte;
+            continue;
+          }
+          else
+          {
+            UpdateBit1(prob);
+          }
+        }
+        else
+        {
+          UInt32 distance;
+          UpdateBit1(prob);
+          prob = p + IsRepG1 + state;
+          IfBit0(prob)
+          {
+            UpdateBit0(prob);
+            distance = rep1;
+          }
+          else 
+          {
+            UpdateBit1(prob);
+            prob = p + IsRepG2 + state;
+            IfBit0(prob)
+            {
+              UpdateBit0(prob);
+              distance = rep2;
+            }
+            else
+            {
+              UpdateBit1(prob);
+              distance = rep3;
+              rep3 = rep2;
+            }
+            rep2 = rep1;
+          }
+          rep1 = rep0;
+          rep0 = distance;
+        }
+        state = state < kNumLitStates ? 8 : 11;
+        prob = p + RepLenCoder;
+      }
+      {
+        int numBits, offset;
+        CProb *probLen = prob + LenChoice;
+        IfBit0(probLen)
+        {
+          UpdateBit0(probLen);
+          probLen = prob + LenLow + (posState << kLenNumLowBits);
+          offset = 0;
+          numBits = kLenNumLowBits;
+        }
+        else
+        {
+          UpdateBit1(probLen);
+          probLen = prob + LenChoice2;
+          IfBit0(probLen)
+          {
+            UpdateBit0(probLen);
+            probLen = prob + LenMid + (posState << kLenNumMidBits);
+            offset = kLenNumLowSymbols;
+            numBits = kLenNumMidBits;
+          }
+          else
+          {
+            UpdateBit1(probLen);
+            probLen = prob + LenHigh;
+            offset = kLenNumLowSymbols + kLenNumMidSymbols;
+            numBits = kLenNumHighBits;
+          }
+        }
+        RangeDecoderBitTreeDecode(probLen, numBits, len);
+        len += offset;
+      }
+
+      if (state < 4)
+      {
+        int posSlot;
+        state += kNumLitStates;
+        prob = p + PosSlot +
+            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 
+            kNumPosSlotBits);
+        RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
+        if (posSlot >= kStartPosModelIndex)
+        {
+          int numDirectBits = ((posSlot >> 1) - 1);
+          rep0 = (2 | ((UInt32)posSlot & 1));
+          if (posSlot < kEndPosModelIndex)
+          {
+            rep0 <<= numDirectBits;
+            prob = p + SpecPos + rep0 - posSlot - 1;
+          }
+          else
+          {
+            numDirectBits -= kNumAlignBits;
+            do
+            {
+              RC_NORMALIZE
+              Range >>= 1;
+              rep0 <<= 1;
+              if (Code >= Range)
+              {
+                Code -= Range;
+                rep0 |= 1;
+              }
+            }
+            while (--numDirectBits != 0);
+            prob = p + Align;
+            rep0 <<= kNumAlignBits;
+            numDirectBits = kNumAlignBits;
+          }
+          {
+            int i = 1;
+            int mi = 1;
+            do
+            {
+              CProb *prob3 = prob + mi;
+              RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
+              i <<= 1;
+            }
+            while(--numDirectBits != 0);
+          }
+        }
+        else
+          rep0 = posSlot;
+        if (++rep0 == (UInt32)(0))
+        {
+          /* it's for stream version */
+          len = kLzmaStreamWasFinishedId;
+          break;
+        }
+      }
+
+      len += kMatchMinLen;
+      if (rep0 > distanceLimit) 
+        return LZMA_RESULT_DATA_ERROR;
+      if (dictionarySize - distanceLimit > (UInt32)len)
+        distanceLimit += len;
+      else
+        distanceLimit = dictionarySize;
+
+      do
+      {
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        previousByte = dictionary[pos];
+        dictionary[dictionaryPos] = previousByte;
+        if (++dictionaryPos == dictionarySize)
+          dictionaryPos = 0;
+        len--;
+        outStream[nowPos++] = previousByte;
+      }
+      while(len != 0 && nowPos < outSize);
+    }
+    }
+  }
+  RC_NORMALIZE;
+
+  BufferSize -= (int)(Buffer - vs->Buffer);
+  if (BufferSize < 0)
+    return LZMA_RESULT_DATA_ERROR;
+  {
+    int i;
+    for (i = 0; i < BufferSize; i++)
+      vs->Buffer[i] = Buffer[i];
+  }
+  vs->BufferSize = BufferSize;
+  vs->Range = Range;
+  vs->Code = Code;
+  vs->DictionaryPos = dictionaryPos;
+  vs->GlobalPos = (UInt32)(globalPos + nowPos);
+  vs->DistanceLimit = distanceLimit;
+  vs->Reps[0] = rep0;
+  vs->Reps[1] = rep1;
+  vs->Reps[2] = rep2;
+  vs->Reps[3] = rep3;
+  vs->State = state;
+  vs->RemainLen = len;
+  vs->TempDictionary[0] = tempDictionary[0];
+
+  (*outSizeProcessed) = nowPos;
+  return LZMA_RESULT_OK;
+}

+ 96 - 0
lzma/C/Compress/Lzma/LzmaStateDecode.h

@@ -0,0 +1,96 @@
+/* 
+  LzmaStateDecode.h
+  LZMA Decoder interface (State version)
+
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this code, expressly permits you to 
+  statically or dynamically link your code (or bind by name) to the 
+  interfaces of this file without subjecting your linked code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMASTATEDECODE_H
+#define __LZMASTATEDECODE_H
+
+#include "LzmaTypes.h"
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs, 
+   but memory usage will be doubled in that case */
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb UInt16
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+  int lc;
+  int lp;
+  int pb;
+  UInt32 DictionarySize;
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(lzmaProps) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((lzmaProps)->lc + (lzmaProps)->lp)))
+
+#define kLzmaInBufferSize 64   /* don't change it. it must be larger than kRequiredInBufferSize */
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+  CLzmaProperties Properties;
+  CProb *Probs;
+  unsigned char *Dictionary;
+
+  unsigned char Buffer[kLzmaInBufferSize];
+  int BufferSize;
+
+  UInt32 Range;
+  UInt32 Code;
+  UInt32 DictionaryPos;
+  UInt32 GlobalPos;
+  UInt32 DistanceLimit;
+  UInt32 Reps[4];
+  int State;
+  int RemainLen;  /* -2: decoder needs internal initialization
+                     -1: stream was finished, 
+                      0: ok
+                    > 0: need to write RemainLen bytes as match Reps[0],
+                  */
+  unsigned char TempDictionary[4];  /* it's required when DictionarySize = 0 */
+} CLzmaDecoderState;
+
+#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; (vs)->BufferSize = 0; }
+
+/* LzmaDecode: decoding from input stream to output stream.
+  If finishDecoding != 0, then there are no more bytes in input stream
+  after inStream[inSize - 1]. */
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    const unsigned char *inStream, SizeT inSize,  SizeT *inSizeProcessed,
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed,
+    int finishDecoding);
+
+#endif

+ 195 - 0
lzma/C/Compress/Lzma/LzmaStateTest.c

@@ -0,0 +1,195 @@
+/* 
+LzmaStateTest.c
+Test application for LZMA Decoder (State version)
+
+This file written and distributed to public domain by Igor Pavlov.
+This file is part of LZMA SDK 4.26 (2005-08-02)
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "LzmaStateDecode.h"
+
+const char *kCantReadMessage = "Can not read input file";
+const char *kCantWriteMessage = "Can not write output file";
+const char *kCantAllocateMessage = "Can not allocate memory";
+
+#define kInBufferSize (1 << 15)
+#define kOutBufferSize (1 << 15)
+
+unsigned char g_InBuffer[kInBufferSize];
+unsigned char g_OutBuffer[kOutBufferSize];
+
+size_t MyReadFile(FILE *file, void *data, size_t size)
+  { return fread(data, 1, size, file); }
+
+int MyReadFileAndCheck(FILE *file, void *data, size_t size)
+  { return (MyReadFile(file, data, size) == size); }
+
+int PrintError(char *buffer, const char *message)
+{
+  sprintf(buffer + strlen(buffer), "\nError: ");
+  sprintf(buffer + strlen(buffer), message);
+  return 1;
+}
+
+int main3(FILE *inFile, FILE *outFile, char *rs)
+{
+  /* We use two 32-bit integers to construct 64-bit integer for file size.
+     You can remove outSizeHigh, if you don't need >= 4GB supporting,
+     or you can use UInt64 outSize, if your compiler supports 64-bit integers*/
+  UInt32 outSize = 0;
+  UInt32 outSizeHigh = 0; 
+  
+  int waitEOS = 1; 
+  /* waitEOS = 1, if there is no uncompressed size in headers, 
+   so decoder will wait EOS (End of Stream Marker) in compressed stream */
+
+  int i;
+  int res = 0;
+  CLzmaDecoderState state;  /* it's about 140 bytes structure, if int is 32-bit */
+  unsigned char properties[LZMA_PROPERTIES_SIZE];
+  SizeT inAvail = 0;
+  unsigned char *inBuffer = 0;
+
+  if (sizeof(UInt32) < 4)
+    return PrintError(rs, "LZMA decoder needs correct UInt32");
+
+  /* Read LZMA properties for compressed stream */
+
+  if (!MyReadFileAndCheck(inFile, properties, sizeof(properties)))
+    return PrintError(rs, kCantReadMessage);
+
+  /* Read uncompressed size */
+  
+  for (i = 0; i < 8; i++)
+  {
+    unsigned char b;
+    if (!MyReadFileAndCheck(inFile, &b, 1))
+      return PrintError(rs, kCantReadMessage);
+    if (b != 0xFF)
+      waitEOS = 0;
+    if (i < 4)
+      outSize += (UInt32)(b) << (i * 8);
+    else
+      outSizeHigh += (UInt32)(b) << ((i - 4) * 8);
+  }
+
+  /* Decode LZMA properties and allocate memory */
+  
+  if (LzmaDecodeProperties(&state.Properties, properties, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK)
+    return PrintError(rs, "Incorrect stream properties");
+  state.Probs = (CProb *)malloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
+  if (state.Probs == 0)
+    return PrintError(rs, kCantAllocateMessage);
+  
+  if (state.Properties.DictionarySize == 0)
+    state.Dictionary = 0;
+  else
+  {
+    state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize);
+    if (state.Dictionary == 0)
+    {
+      free(state.Probs);
+      return PrintError(rs, kCantAllocateMessage);
+    }
+  }
+  
+  /* Decompress */
+  
+  LzmaDecoderInit(&state);
+  
+  do
+  {
+    SizeT inProcessed, outProcessed;
+    int finishDecoding;
+    UInt32 outAvail = kOutBufferSize;
+    if (!waitEOS && outSizeHigh == 0 && outAvail > outSize)
+      outAvail = outSize;
+    if (inAvail == 0)
+    {
+      inAvail = (SizeT)MyReadFile(inFile, g_InBuffer, kInBufferSize);
+      inBuffer = g_InBuffer;
+    }
+    finishDecoding = (inAvail == 0);
+    res = LzmaDecode(&state,
+        inBuffer, inAvail, &inProcessed,
+        g_OutBuffer, outAvail, &outProcessed,
+        finishDecoding);
+    if (res != 0)
+    {
+      sprintf(rs + strlen(rs), "\nDecoding error = %d\n", res);
+      res = 1;
+      break;
+    }
+    inAvail -= inProcessed;
+    inBuffer += inProcessed;
+    
+    if (outFile != 0)  
+      if (fwrite(g_OutBuffer, 1, outProcessed, outFile) != outProcessed)
+      {
+        PrintError(rs, kCantWriteMessage);
+        res = 1;
+        break;
+      }
+      
+    if (outSize < outProcessed)
+      outSizeHigh--;
+    outSize -= (UInt32)outProcessed;
+    outSize &= 0xFFFFFFFF;
+
+    if (outProcessed == 0 && finishDecoding)
+    {
+      if (!waitEOS && (outSize != 0 || outSizeHigh != 0))
+        res = 1;
+      break;
+    }
+  }
+  while ((outSize != 0 && outSizeHigh == 0) || outSizeHigh != 0  || waitEOS);
+
+  free(state.Dictionary);
+  free(state.Probs);
+  return res;
+}
+
+int main2(int numArgs, const char *args[], char *rs)
+{
+  FILE *inFile = 0;
+  FILE *outFile = 0;
+  int res;
+
+  sprintf(rs + strlen(rs), "\nLZMA Decoder 4.26 Copyright (c) 1999-2005 Igor Pavlov  2005-08-02\n");
+  if (numArgs < 2 || numArgs > 3)
+  {
+    sprintf(rs + strlen(rs), "\nUsage:  lzmadec file.lzma [outFile]\n");
+    return 1;
+  }
+
+  inFile = fopen(args[1], "rb");
+  if (inFile == 0)
+    return PrintError(rs, "Can not open input file");
+
+  if (numArgs > 2)
+  {
+    outFile = fopen(args[2], "wb+");
+    if (outFile == 0)
+      return PrintError(rs, "Can not open output file");
+  }
+
+  res = main3(inFile, outFile, rs);
+
+  if (outFile != 0)
+    fclose(outFile);
+  fclose(inFile);
+  return res;
+}
+
+int main(int numArgs, const char *args[])
+{
+  char rs[800] = { 0 };
+  int res = main2(numArgs, args, rs);
+  printf(rs);
+  return res;
+}

+ 342 - 0
lzma/C/Compress/Lzma/LzmaTest.c

@@ -0,0 +1,342 @@
+/* 
+LzmaTest.c
+Test application for LZMA Decoder
+
+This file written and distributed to public domain by Igor Pavlov.
+This file is part of LZMA SDK 4.26 (2005-08-05)
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "LzmaDecode.h"
+
+const char *kCantReadMessage = "Can not read input file";
+const char *kCantWriteMessage = "Can not write output file";
+const char *kCantAllocateMessage = "Can not allocate memory";
+
+size_t MyReadFile(FILE *file, void *data, size_t size)
+{ 
+  if (size == 0)
+    return 0;
+  return fread(data, 1, size, file); 
+}
+
+int MyReadFileAndCheck(FILE *file, void *data, size_t size)
+  { return (MyReadFile(file, data, size) == size);} 
+
+size_t MyWriteFile(FILE *file, const void *data, size_t size)
+{ 
+  if (size == 0)
+    return 0;
+  return fwrite(data, 1, size, file); 
+}
+
+int MyWriteFileAndCheck(FILE *file, const void *data, size_t size)
+  { return (MyWriteFile(file, data, size) == size); }
+
+#ifdef _LZMA_IN_CB
+#define kInBufferSize (1 << 15)
+typedef struct _CBuffer
+{
+  ILzmaInCallback InCallback;
+  FILE *File;
+  unsigned char Buffer[kInBufferSize];
+} CBuffer;
+
+int LzmaReadCompressed(void *object, const unsigned char **buffer, SizeT *size)
+{
+  CBuffer *b = (CBuffer *)object;
+  *buffer = b->Buffer;
+  *size = (SizeT)MyReadFile(b->File, b->Buffer, kInBufferSize);
+  return LZMA_RESULT_OK;
+}
+CBuffer g_InBuffer;
+
+#endif
+
+#ifdef _LZMA_OUT_READ
+#define kOutBufferSize (1 << 15)
+unsigned char g_OutBuffer[kOutBufferSize];
+#endif
+
+int PrintError(char *buffer, const char *message)
+{
+  sprintf(buffer + strlen(buffer), "\nError: ");
+  sprintf(buffer + strlen(buffer), message);
+  return 1;
+}
+
+int main3(FILE *inFile, FILE *outFile, char *rs)
+{
+  /* We use two 32-bit integers to construct 64-bit integer for file size.
+     You can remove outSizeHigh, if you don't need >= 4GB supporting,
+     or you can use UInt64 outSize, if your compiler supports 64-bit integers*/
+  UInt32 outSize = 0;
+  UInt32 outSizeHigh = 0;
+  #ifndef _LZMA_OUT_READ
+  SizeT outSizeFull;
+  unsigned char *outStream;
+  #endif
+  
+  int waitEOS = 1; 
+  /* waitEOS = 1, if there is no uncompressed size in headers, 
+   so decoder will wait EOS (End of Stream Marker) in compressed stream */
+
+  #ifndef _LZMA_IN_CB
+  SizeT compressedSize;
+  unsigned char *inStream;
+  #endif
+
+  CLzmaDecoderState state;  /* it's about 24-80 bytes structure, if int is 32-bit */
+  unsigned char properties[LZMA_PROPERTIES_SIZE];
+
+  int res;
+
+  #ifdef _LZMA_IN_CB
+  g_InBuffer.File = inFile;
+  #endif
+
+  if (sizeof(UInt32) < 4)
+    return PrintError(rs, "LZMA decoder needs correct UInt32");
+
+  #ifndef _LZMA_IN_CB
+  {
+    long length;
+    fseek(inFile, 0, SEEK_END);
+    length = ftell(inFile);
+    fseek(inFile, 0, SEEK_SET);
+    if ((long)(SizeT)length != length)
+      return PrintError(rs, "Too big compressed stream");
+    compressedSize = (SizeT)(length - (LZMA_PROPERTIES_SIZE + 8));
+  }
+  #endif
+
+  /* Read LZMA properties for compressed stream */
+
+  if (!MyReadFileAndCheck(inFile, properties, sizeof(properties)))
+    return PrintError(rs, kCantReadMessage);
+
+  /* Read uncompressed size */
+
+  {
+    int i;
+    for (i = 0; i < 8; i++)
+    {
+      unsigned char b;
+      if (!MyReadFileAndCheck(inFile, &b, 1))
+        return PrintError(rs, kCantReadMessage);
+      if (b != 0xFF)
+        waitEOS = 0;
+      if (i < 4)
+        outSize += (UInt32)(b) << (i * 8);
+      else
+        outSizeHigh += (UInt32)(b) << ((i - 4) * 8);
+    }
+    
+    #ifndef _LZMA_OUT_READ
+    if (waitEOS)
+      return PrintError(rs, "Stream with EOS marker is not supported");
+    outSizeFull = (SizeT)outSize;
+    if (sizeof(SizeT) >= 8)
+      outSizeFull |= (((SizeT)outSizeHigh << 16) << 16);
+    else if (outSizeHigh != 0 || (UInt32)(SizeT)outSize != outSize)
+      return PrintError(rs, "Too big uncompressed stream");
+    #endif
+  }
+
+  /* Decode LZMA properties and allocate memory */
+  
+  if (LzmaDecodeProperties(&state.Properties, properties, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK)
+    return PrintError(rs, "Incorrect stream properties");
+  state.Probs = (CProb *)malloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
+
+  #ifdef _LZMA_OUT_READ
+  if (state.Properties.DictionarySize == 0)
+    state.Dictionary = 0;
+  else
+    state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize);
+  #else
+  if (outSizeFull == 0)
+    outStream = 0;
+  else
+    outStream = (unsigned char *)malloc(outSizeFull);
+  #endif
+
+  #ifndef _LZMA_IN_CB
+  if (compressedSize == 0)
+    inStream = 0;
+  else
+    inStream = (unsigned char *)malloc(compressedSize);
+  #endif
+
+  if (state.Probs == 0 
+    #ifdef _LZMA_OUT_READ
+    || (state.Dictionary == 0 && state.Properties.DictionarySize != 0)
+    #else
+    || (outStream == 0 && outSizeFull != 0)
+    #endif
+    #ifndef _LZMA_IN_CB
+    || (inStream == 0 && compressedSize != 0)
+    #endif
+    )
+  {
+    free(state.Probs);
+    #ifdef _LZMA_OUT_READ
+    free(state.Dictionary);
+    #else
+    free(outStream);
+    #endif
+    #ifndef _LZMA_IN_CB
+    free(inStream);
+    #endif
+    return PrintError(rs, kCantAllocateMessage);
+  }
+
+  /* Decompress */
+
+  #ifdef _LZMA_IN_CB
+  g_InBuffer.InCallback.Read = LzmaReadCompressed;
+  #else
+  if (!MyReadFileAndCheck(inFile, inStream, compressedSize))
+    return PrintError(rs, kCantReadMessage);
+  #endif
+
+  #ifdef _LZMA_OUT_READ
+  {
+    #ifndef _LZMA_IN_CB
+    SizeT inAvail = compressedSize;
+    const unsigned char *inBuffer = inStream;
+    #endif
+    LzmaDecoderInit(&state);
+    do
+    {
+      #ifndef _LZMA_IN_CB
+      SizeT inProcessed;
+      #endif
+      SizeT outProcessed;
+      SizeT outAvail = kOutBufferSize;
+      if (!waitEOS && outSizeHigh == 0 && outAvail > outSize)
+        outAvail = (SizeT)outSize;
+      res = LzmaDecode(&state,
+        #ifdef _LZMA_IN_CB
+        &g_InBuffer.InCallback,
+        #else
+        inBuffer, inAvail, &inProcessed,
+        #endif
+        g_OutBuffer, outAvail, &outProcessed);
+      if (res != 0)
+      {
+        sprintf(rs + strlen(rs), "\nDecoding error = %d\n", res);
+        res = 1;
+        break;
+      }
+      #ifndef _LZMA_IN_CB
+      inAvail -= inProcessed;
+      inBuffer += inProcessed;
+      #endif
+      
+      if (outFile != 0)  
+        if (!MyWriteFileAndCheck(outFile, g_OutBuffer, (size_t)outProcessed))
+        {
+          PrintError(rs, kCantWriteMessage);
+          res = 1;
+          break;
+        }
+        
+      if (outSize < outProcessed)
+        outSizeHigh--;
+      outSize -= (UInt32)outProcessed;
+      outSize &= 0xFFFFFFFF;
+        
+      if (outProcessed == 0)
+      {
+        if (!waitEOS && (outSize != 0 || outSizeHigh != 0))
+          res = 1;
+        break;
+      }
+    }
+    while ((outSize != 0 && outSizeHigh == 0) || outSizeHigh != 0  || waitEOS);
+  }
+
+  #else
+  {
+    #ifndef _LZMA_IN_CB
+    SizeT inProcessed;
+    #endif
+    SizeT outProcessed;
+    res = LzmaDecode(&state,
+      #ifdef _LZMA_IN_CB
+      &g_InBuffer.InCallback,
+      #else
+      inStream, compressedSize, &inProcessed,
+      #endif
+      outStream, outSizeFull, &outProcessed);
+    if (res != 0)
+    {
+      sprintf(rs + strlen(rs), "\nDecoding error = %d\n", res);
+      res = 1;
+    }
+    else if (outFile != 0)
+    {
+      if (!MyWriteFileAndCheck(outFile, outStream, (size_t)outProcessed))
+      {
+        PrintError(rs, kCantWriteMessage);
+        res = 1;
+      }
+    }
+  }
+  #endif
+
+  free(state.Probs);
+  #ifdef _LZMA_OUT_READ
+  free(state.Dictionary);
+  #else
+  free(outStream);
+  #endif
+  #ifndef _LZMA_IN_CB
+  free(inStream);
+  #endif
+  return res;
+}
+
+int main2(int numArgs, const char *args[], char *rs)
+{
+  FILE *inFile = 0;
+  FILE *outFile = 0;
+  int res;
+
+  sprintf(rs + strlen(rs), "\nLZMA Decoder 4.26 Copyright (c) 1999-2005 Igor Pavlov  2005-08-05\n");
+  if (numArgs < 2 || numArgs > 3)
+  {
+    sprintf(rs + strlen(rs), "\nUsage:  lzmadec file.lzma [outFile]\n");
+    return 1;
+  }
+
+  inFile = fopen(args[1], "rb");
+  if (inFile == 0)
+    return PrintError(rs, "Can not open input file");
+
+  if (numArgs > 2)
+  {
+    outFile = fopen(args[2], "wb+");
+    if (outFile == 0)
+      return PrintError(rs, "Can not open output file");
+  }
+
+  res = main3(inFile, outFile, rs);
+
+  if (outFile != 0)
+    fclose(outFile);
+  fclose(inFile);
+  return res;
+}
+
+int main(int numArgs, const char *args[])
+{
+  char rs[800] = { 0 };
+  int res = main2(numArgs, args, rs);
+  printf(rs);
+  return res;
+}

+ 45 - 0
lzma/C/Compress/Lzma/LzmaTypes.h

@@ -0,0 +1,45 @@
+/* 
+LzmaTypes.h 
+
+Types for LZMA Decoder
+
+This file written and distributed to public domain by Igor Pavlov.
+This file is part of LZMA SDK 4.40 (2006-05-01)
+*/
+
+#ifndef __LZMATYPES_H
+#define __LZMATYPES_H
+
+#ifndef _7ZIP_BYTE_DEFINED
+#define _7ZIP_BYTE_DEFINED
+typedef unsigned char Byte;
+#endif 
+
+#ifndef _7ZIP_UINT16_DEFINED
+#define _7ZIP_UINT16_DEFINED
+typedef unsigned short UInt16;
+#endif 
+
+#ifndef _7ZIP_UINT32_DEFINED
+#define _7ZIP_UINT32_DEFINED
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef unsigned long UInt32;
+#else
+typedef unsigned int UInt32;
+#endif
+#endif 
+
+/* #define _LZMA_NO_SYSTEM_SIZE_T */
+/* You can use it, if you don't want <stddef.h> */
+
+#ifndef _7ZIP_SIZET_DEFINED
+#define _7ZIP_SIZET_DEFINED
+#ifdef _LZMA_NO_SYSTEM_SIZE_T
+typedef UInt32 SizeT;
+#else
+#include <stddef.h>
+typedef size_t SizeT;
+#endif
+#endif
+
+#endif

+ 18 - 0
lzma/C/CpuArch.h

@@ -0,0 +1,18 @@
+/* CpuArch.h */
+
+#ifndef __CPUARCH_H
+#define __CPUARCH_H
+
+/* 
+LITTLE_ENDIAN_UNALIGN means:
+  1) CPU is LITTLE_ENDIAN
+  2) it's allowed to make unaligned memory accesses
+if LITTLE_ENDIAN_UNALIGN is not defined, it means that we don't know 
+about these properties of platform.
+*/
+
+#if defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || defined(__x86_64__)
+#define LITTLE_ENDIAN_UNALIGN
+#endif
+
+#endif

+ 19 - 0
lzma/C/IStream.h

@@ -0,0 +1,19 @@
+/* IStream.h */
+
+#ifndef __C_ISTREAM_H
+#define __C_ISTREAM_H
+
+#include "Types.h"
+
+typedef struct _ISeqInStream
+{
+  HRes (*Read)(void *object, void *data, UInt32 size, UInt32 *processedSize);
+} ISeqInStream;
+
+typedef struct _ISzAlloc
+{
+  void *(*Alloc)(size_t size);
+  void (*Free)(void *address); /* address can be 0 */
+} ISzAlloc;
+
+#endif

+ 92 - 0
lzma/C/Sort.c

@@ -0,0 +1,92 @@
+/* Sort.c */
+
+#include "Sort.h"
+
+#define HeapSortDown(p, k, size, temp) \
+  { for (;;) { \
+    UInt32 s = (k << 1); \
+    if (s > size) break; \
+    if (s < size && p[s + 1] > p[s]) s++; \
+    if (temp >= p[s]) break; \
+    p[k] = p[s]; k = s; \
+  } p[k] = temp; }
+
+void HeapSort(UInt32 *p, UInt32 size)
+{
+  if (size <= 1)
+    return;
+  p--;
+  {
+    UInt32 i = size / 2;
+    do
+    {
+      UInt32 temp = p[i];
+      UInt32 k = i;
+      HeapSortDown(p, k, size, temp)
+    }
+    while(--i != 0);
+  }
+  /*
+  do
+  {
+    UInt32 k = 1;
+    UInt32 temp = p[size];
+    p[size--] = p[1];
+    HeapSortDown(p, k, size, temp)
+  }
+  while (size > 1);
+  */
+  while (size > 3)
+  {
+    UInt32 temp = p[size];
+    UInt32 k = (p[3] > p[2]) ? 3 : 2;
+    p[size--] = p[1];
+    p[1] = p[k]; 
+    HeapSortDown(p, k, size, temp)
+  }
+  {
+    UInt32 temp = p[size];
+    p[size] = p[1];
+    if (size > 2 && p[2] < temp)
+    {
+      p[1] = p[2];
+      p[2] = temp;
+    }
+    else
+      p[1] = temp;
+  }
+}
+
+/*
+#define HeapSortRefDown(p, vals, n, size, temp) \
+  { UInt32 k = n; UInt32 val = vals[temp]; for (;;) { \
+    UInt32 s = (k << 1); \
+    if (s > size) break; \
+    if (s < size && vals[p[s + 1]] > vals[p[s]]) s++; \
+    if (val >= vals[p[s]]) break; \
+    p[k] = p[s]; k = s; \
+  } p[k] = temp; }
+
+void HeapSortRef(UInt32 *p, UInt32 *vals, UInt32 size)
+{
+  if (size <= 1)
+    return;
+  p--;
+  {
+    UInt32 i = size / 2;
+    do
+    {
+      UInt32 temp = p[i];
+      HeapSortRefDown(p, vals, i, size, temp);
+    }
+    while(--i != 0);
+  }
+  do
+  {
+    UInt32 temp = p[size];
+    p[size--] = p[1];
+    HeapSortRefDown(p, vals, 1, size, temp);
+  }
+  while (size > 1);
+}
+*/

+ 11 - 0
lzma/C/Sort.h

@@ -0,0 +1,11 @@
+/* Sort.h */
+
+#ifndef __7Z_Sort_H
+#define __7Z_Sort_H
+
+#include "Types.h"
+
+void HeapSort(UInt32 *p, UInt32 size);
+/* void HeapSortRef(UInt32 *p, UInt32 *vals, UInt32 size); */
+
+#endif

+ 106 - 0
lzma/C/Threads.c

@@ -0,0 +1,106 @@
+/* Threads.c */
+
+#include "Threads.h"
+#include <process.h>
+
+HRes GetError()
+{
+  DWORD res = GetLastError();
+  return (res) ? (HRes)(res) : SZE_FAIL;
+}
+
+HRes BoolToHRes(int v) { return v ? SZ_OK : GetError(); }
+HRes BOOLToHRes(BOOL v) { return v ? SZ_OK : GetError(); }
+
+HRes MyCloseHandle(HANDLE *h)
+{
+  if (*h != NULL)
+    if (!CloseHandle(*h))
+      return GetError();
+  *h = NULL;
+  return SZ_OK;
+}
+
+HRes Thread_Create(CThread *thread, THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter)
+{ 
+  unsigned threadId; /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
+  thread->handle = 
+    /* CreateThread(0, 0, startAddress, parameter, 0, &threadId); */
+    (HANDLE)_beginthreadex(NULL, 0, startAddress, parameter, 0, &threadId);
+    /* maybe we must use errno here, but probably GetLastError() is also OK. */
+  return BoolToHRes(thread->handle != 0);
+}
+
+HRes WaitObject(HANDLE h)
+{
+  return (HRes)WaitForSingleObject(h, INFINITE); 
+}
+
+HRes Thread_Wait(CThread *thread)
+{
+  if (thread->handle == NULL)
+    return 1;
+  return WaitObject(thread->handle); 
+}
+
+HRes Thread_Close(CThread *thread)
+{
+  return MyCloseHandle(&thread->handle);
+}
+
+HRes Event_Create(CEvent *p, BOOL manualReset, int initialSignaled)
+{
+  p->handle = CreateEvent(NULL, manualReset, (initialSignaled ? TRUE : FALSE), NULL);
+  return BoolToHRes(p->handle != 0);
+}
+
+HRes ManualResetEvent_Create(CManualResetEvent *p, int initialSignaled)
+  { return Event_Create(p, TRUE, initialSignaled); }
+HRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) 
+  { return ManualResetEvent_Create(p, 0); }
+
+HRes AutoResetEvent_Create(CAutoResetEvent *p, int initialSignaled)
+  { return Event_Create(p, FALSE, initialSignaled); }
+HRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) 
+  { return AutoResetEvent_Create(p, 0); }
+
+HRes Event_Set(CEvent *p) { return BOOLToHRes(SetEvent(p->handle)); }
+HRes Event_Reset(CEvent *p) { return BOOLToHRes(ResetEvent(p->handle)); }
+HRes Event_Wait(CEvent *p) { return WaitObject(p->handle); }
+HRes Event_Close(CEvent *p) { return MyCloseHandle(&p->handle); }
+
+
+HRes Semaphore_Create(CSemaphore *p, UInt32 initiallyCount, UInt32 maxCount)
+{
+  p->handle = CreateSemaphore(NULL, (LONG)initiallyCount, (LONG)maxCount, NULL);
+  return BoolToHRes(p->handle != 0);
+}
+
+HRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount) 
+{ 
+  return BOOLToHRes(ReleaseSemaphore(p->handle, releaseCount, previousCount)); 
+}
+HRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount)
+{
+  return Semaphore_Release(p, (LONG)releaseCount, NULL);
+}
+HRes Semaphore_Release1(CSemaphore *p)
+{
+  return Semaphore_ReleaseN(p, 1);
+}
+
+HRes Semaphore_Wait(CSemaphore *p) { return WaitObject(p->handle); }
+HRes Semaphore_Close(CSemaphore *p) { return MyCloseHandle(&p->handle); }
+
+HRes CriticalSection_Init(CCriticalSection *p)
+{
+  /* InitializeCriticalSection can raise only STATUS_NO_MEMORY exception */
+  __try 
+  { 
+    InitializeCriticalSection(p); 
+    /* InitializeCriticalSectionAndSpinCount(p, 0); */
+  }  
+  __except (EXCEPTION_EXECUTE_HANDLER) { return SZE_OUTOFMEMORY; }
+  return SZ_OK;
+}
+

+ 69 - 0
lzma/C/Threads.h

@@ -0,0 +1,69 @@
+/* Threads.h */
+
+#ifndef __7Z_THRESDS_H
+#define __7Z_THRESDS_H
+
+#include <windows.h>
+
+#include "Types.h"
+
+typedef struct _CThread
+{
+  HANDLE handle;
+} CThread;
+
+#define Thread_Construct(thread) (thread)->handle = NULL
+#define Thread_WasCreated(thread) ((thread)->handle != NULL)
+ 
+typedef unsigned THREAD_FUNC_RET_TYPE;
+#define THREAD_FUNC_CALL_TYPE StdCall
+#define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE
+
+HRes Thread_Create(CThread *thread, THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter);
+HRes Thread_Wait(CThread *thread);
+HRes Thread_Close(CThread *thread);
+
+typedef struct _CEvent
+{
+  HANDLE handle;
+} CEvent;
+
+typedef CEvent CAutoResetEvent;
+typedef CEvent CManualResetEvent;
+
+#define Event_Construct(event) (event)->handle = NULL
+#define Event_IsCreated(event) ((event)->handle != NULL)
+
+HRes ManualResetEvent_Create(CManualResetEvent *event, int initialSignaled);
+HRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *event);
+HRes AutoResetEvent_Create(CAutoResetEvent *event, int initialSignaled);
+HRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *event);
+HRes Event_Set(CEvent *event);
+HRes Event_Reset(CEvent *event);
+HRes Event_Wait(CEvent *event);
+HRes Event_Close(CEvent *event);
+
+
+typedef struct _CSemaphore
+{
+  HANDLE handle;
+} CSemaphore;
+
+#define Semaphore_Construct(p) (p)->handle = NULL
+
+HRes Semaphore_Create(CSemaphore *p, UInt32 initiallyCount, UInt32 maxCount);
+HRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num);
+HRes Semaphore_Release1(CSemaphore *p);
+HRes Semaphore_Wait(CSemaphore *p);
+HRes Semaphore_Close(CSemaphore *p);
+
+
+typedef CRITICAL_SECTION CCriticalSection;
+
+HRes CriticalSection_Init(CCriticalSection *p);
+#define CriticalSection_Delete(p) DeleteCriticalSection(p)
+#define CriticalSection_Enter(p) EnterCriticalSection(p)
+#define CriticalSection_Leave(p) LeaveCriticalSection(p)
+
+#endif
+

+ 100 - 0
lzma/C/Types.h

@@ -0,0 +1,100 @@
+/* 7zTypes.h */
+
+#ifndef __C_TYPES_H
+#define __C_TYPES_H
+
+#ifndef _7ZIP_BYTE_DEFINED
+#define _7ZIP_BYTE_DEFINED
+typedef unsigned char Byte;
+#endif 
+
+#ifndef _7ZIP_UINT16_DEFINED
+#define _7ZIP_UINT16_DEFINED
+typedef unsigned short UInt16;
+#endif 
+
+#ifndef _7ZIP_UINT32_DEFINED
+#define _7ZIP_UINT32_DEFINED
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef unsigned long UInt32;
+#else
+typedef unsigned int UInt32;
+#endif
+#endif 
+
+#ifndef _7ZIP_INT32_DEFINED
+#define _7ZIP_INT32_DEFINED
+#ifdef _LZMA_INT32_IS_ULONG
+typedef long Int32;
+#else
+typedef int Int32;
+#endif
+#endif 
+
+/* #define _SZ_NO_INT_64 */
+/* define it your compiler doesn't support long long int */
+
+#ifndef _7ZIP_UINT64_DEFINED
+#define _7ZIP_UINT64_DEFINED
+#ifdef _SZ_NO_INT_64
+typedef unsigned long UInt64;
+#else
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef unsigned __int64 UInt64;
+#else
+typedef unsigned long long int UInt64;
+#endif
+#endif
+#endif
+
+
+/* #define _SZ_FILE_SIZE_32 */
+/* You can define _SZ_FILE_SIZE_32, if you don't need support for files larger than 4 GB*/
+
+#ifndef CFileSize
+#ifdef _SZ_FILE_SIZE_32
+typedef UInt32 CFileSize; 
+#else
+typedef UInt64 CFileSize; 
+#endif
+#endif
+
+#define SZ_RESULT int
+
+typedef int HRes;
+#define RES_OK (0)
+
+#define SZ_OK (0)
+#define SZE_DATA_ERROR (1)
+#define SZE_CRC_ERROR (3)
+#define SZE_ARCHIVE_ERROR (6)
+
+#define SZE_OUTOFMEMORY (0x8007000EL)
+#define SZE_NOTIMPL (0x80004001L)
+#define SZE_FAIL (0x80004005L)
+#define SZE_INVALIDARG (0x80070057L)
+
+
+#ifndef RINOK
+#define RINOK(x) { HRes __result_ = (x); if(__result_ != 0) return __result_; }
+#endif
+
+typedef int Bool;
+#define True 1
+#define False 0
+
+#ifdef _MSC_VER
+#define StdCall __stdcall 
+#else
+#define StdCall
+#endif
+
+#if _MSC_VER >= 1300
+#define MY_FAST_CALL __declspec(noinline) __fastcall 
+#elif defined( _MSC_VER)
+#define MY_FAST_CALL __fastcall 
+#else
+#define MY_FAST_CALL
+#endif
+
+#endif

BIN
lzma/CPP/7zip/Archive/7z/7z.ico


+ 3 - 0
lzma/CPP/7zip/Archive/7z/7zCompressionMode.cpp

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

+ 50 - 0
lzma/CPP/7zip/Archive/7z/7zCompressionMode.h

@@ -0,0 +1,50 @@
+// 7zCompressionMode.h
+
+#ifndef __7Z_COMPRESSION_MODE_H
+#define __7Z_COMPRESSION_MODE_H
+
+#include "../../../Common/MyString.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../../Common/MethodProps.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CMethodFull: public CMethod
+{
+  UInt32 NumInStreams;
+  UInt32 NumOutStreams;
+  bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); }
+};
+
+struct CBind
+{
+  UInt32 InCoder;
+  UInt32 InStream;
+  UInt32 OutCoder;
+  UInt32 OutStream;
+};
+
+struct CCompressionMethodMode
+{
+  CObjectVector<CMethodFull> Methods;
+  CRecordVector<CBind> Binds;
+  #ifdef COMPRESS_MT
+  UInt32 NumThreads;
+  #endif
+  bool PasswordIsDefined;
+  UString Password;
+
+  bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); }
+  CCompressionMethodMode(): PasswordIsDefined(false)
+      #ifdef COMPRESS_MT
+      , NumThreads(1) 
+      #endif
+  {}
+};
+
+}}
+
+#endif

+ 330 - 0
lzma/CPP/7zip/Archive/7z/7zDecode.cpp

@@ -0,0 +1,330 @@
+// 7zDecode.cpp
+
+#include "StdAfx.h"
+
+#include "7zDecode.h"
+
+#include "../../IPassword.h"
+#include "../../Common/LockedStream.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/CreateCoder.h"
+#include "../../Common/FilterCoder.h"
+
+namespace NArchive {
+namespace N7z {
+
+static void ConvertFolderItemInfoToBindInfo(const CFolder &folder,
+    CBindInfoEx &bindInfo)
+{
+  bindInfo.Clear();
+  int i;
+  for (i = 0; i < folder.BindPairs.Size(); i++)
+  {
+    NCoderMixer::CBindPair bindPair;
+    bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex;
+    bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex;
+    bindInfo.BindPairs.Add(bindPair);
+  }
+  UInt32 outStreamIndex = 0;
+  for (i = 0; i < folder.Coders.Size(); i++)
+  {
+    NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+    const CCoderInfo &coderInfo = folder.Coders[i];
+    coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams;
+    coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams;
+    bindInfo.Coders.Add(coderStreamsInfo);
+    bindInfo.CoderMethodIDs.Add(coderInfo.MethodID);
+    for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++)
+      if (folder.FindBindPairForOutStream(outStreamIndex) < 0)
+        bindInfo.OutStreams.Add(outStreamIndex);
+  }
+  for (i = 0; i < folder.PackStreams.Size(); i++)
+    bindInfo.InStreams.Add((UInt32)folder.PackStreams[i]);
+}
+
+static bool AreCodersEqual(const NCoderMixer::CCoderStreamsInfo &a1, 
+    const NCoderMixer::CCoderStreamsInfo &a2)
+{
+  return (a1.NumInStreams == a2.NumInStreams) &&
+    (a1.NumOutStreams == a2.NumOutStreams);
+}
+
+static bool AreBindPairsEqual(const NCoderMixer::CBindPair &a1, const NCoderMixer::CBindPair &a2)
+{
+  return (a1.InIndex == a2.InIndex) &&
+    (a1.OutIndex == a2.OutIndex);
+}
+
+static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2)
+{
+  if (a1.Coders.Size() != a2.Coders.Size())
+    return false;
+  int i;
+  for (i = 0; i < a1.Coders.Size(); i++)
+    if (!AreCodersEqual(a1.Coders[i], a2.Coders[i]))
+      return false;
+  if (a1.BindPairs.Size() != a2.BindPairs.Size())
+    return false;
+  for (i = 0; i < a1.BindPairs.Size(); i++)
+    if (!AreBindPairsEqual(a1.BindPairs[i], a2.BindPairs[i]))
+      return false;
+  for (i = 0; i < a1.CoderMethodIDs.Size(); i++)
+    if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i])
+      return false;
+  if (a1.InStreams.Size() != a2.InStreams.Size())
+    return false;
+  if (a1.OutStreams.Size() != a2.OutStreams.Size())
+    return false;
+  return true;
+}
+
+CDecoder::CDecoder(bool multiThread)
+{
+  #ifndef _ST_MODE
+  multiThread = true;
+  #endif
+  _multiThread = multiThread;
+  _bindInfoExPrevIsDefined = false;
+}
+
+HRESULT CDecoder::Decode(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    IInStream *inStream,
+    UInt64 startPos,
+    const UInt64 *packSizes,
+    const CFolder &folderInfo, 
+    ISequentialOutStream *outStream,
+    ICompressProgressInfo *compressProgress
+    #ifndef _NO_CRYPTO
+    , ICryptoGetTextPassword *getTextPassword
+    #endif
+    #ifdef COMPRESS_MT
+    , bool mtMode, UInt32 numThreads
+    #endif
+    )
+{
+  CObjectVector< CMyComPtr<ISequentialInStream> > inStreams;
+  
+  CLockedInStream lockedInStream;
+  lockedInStream.Init(inStream);
+  
+  for (int j = 0; j < folderInfo.PackStreams.Size(); j++)
+  {
+    CLockedSequentialInStreamImp *lockedStreamImpSpec = new 
+        CLockedSequentialInStreamImp;
+    CMyComPtr<ISequentialInStream> lockedStreamImp = lockedStreamImpSpec;
+    lockedStreamImpSpec->Init(&lockedInStream, startPos);
+    startPos += packSizes[j];
+    
+    CLimitedSequentialInStream *streamSpec = new 
+        CLimitedSequentialInStream;
+    CMyComPtr<ISequentialInStream> inStream = streamSpec;
+    streamSpec->SetStream(lockedStreamImp);
+    streamSpec->Init(packSizes[j]);
+    inStreams.Add(inStream);
+  }
+  
+  int numCoders = folderInfo.Coders.Size();
+  
+  CBindInfoEx bindInfo;
+  ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo);
+  bool createNewCoders;
+  if (!_bindInfoExPrevIsDefined)
+    createNewCoders = true;
+  else
+    createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev);
+  if (createNewCoders)
+  {
+    int i;
+    _decoders.Clear();
+    // _decoders2.Clear();
+    
+    _mixerCoder.Release();
+
+    if (_multiThread)
+    {
+      _mixerCoderMTSpec = new NCoderMixer::CCoderMixer2MT;
+      _mixerCoder = _mixerCoderMTSpec;
+      _mixerCoderCommon = _mixerCoderMTSpec;
+    }
+    else
+    {
+      #ifdef _ST_MODE
+      _mixerCoderSTSpec = new NCoderMixer::CCoderMixer2ST;
+      _mixerCoder = _mixerCoderSTSpec;
+      _mixerCoderCommon = _mixerCoderSTSpec;
+      #endif
+    }
+    RINOK(_mixerCoderCommon->SetBindInfo(bindInfo));
+    
+    for (i = 0; i < numCoders; i++)
+    {
+      const CCoderInfo &coderInfo = folderInfo.Coders[i];
+
+  
+      CMyComPtr<ICompressCoder> decoder;
+      CMyComPtr<ICompressCoder2> decoder2;
+      RINOK(CreateCoder(
+          EXTERNAL_CODECS_LOC_VARS
+          coderInfo.MethodID, decoder, decoder2, false));
+      CMyComPtr<IUnknown> decoderUnknown;
+      if (coderInfo.IsSimpleCoder())
+      {
+        if (decoder == 0)
+          return E_NOTIMPL;
+
+        decoderUnknown = (IUnknown *)decoder;
+        
+        if (_multiThread)
+          _mixerCoderMTSpec->AddCoder(decoder);
+        #ifdef _ST_MODE
+        else
+          _mixerCoderSTSpec->AddCoder(decoder, false);
+        #endif
+      }
+      else
+      {
+        if (decoder2 == 0)
+          return E_NOTIMPL;
+        decoderUnknown = (IUnknown *)decoder2;
+        if (_multiThread)
+          _mixerCoderMTSpec->AddCoder2(decoder2);
+        #ifdef _ST_MODE
+        else
+          _mixerCoderSTSpec->AddCoder2(decoder2, false);
+        #endif
+      }
+      _decoders.Add(decoderUnknown);
+      #ifdef EXTERNAL_CODECS
+      CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+      decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+      if (setCompressCodecsInfo)
+      {
+        RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo));
+      }
+      #endif
+    }
+    _bindInfoExPrev = bindInfo;
+    _bindInfoExPrevIsDefined = true;
+  }
+  int i;
+  _mixerCoderCommon->ReInit();
+  
+  UInt32 packStreamIndex = 0, unPackStreamIndex = 0;
+  UInt32 coderIndex = 0;
+  // UInt32 coder2Index = 0;
+  
+  for (i = 0; i < numCoders; i++)
+  {
+    const CCoderInfo &coderInfo = folderInfo.Coders[i];
+    CMyComPtr<IUnknown> &decoder = _decoders[coderIndex];
+    
+    {
+      CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
+      decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties);
+      if (setDecoderProperties)
+      {
+        const CByteBuffer &properties = coderInfo.Properties;
+        size_t size = properties.GetCapacity();
+        if (size > 0xFFFFFFFF)
+          return E_NOTIMPL;
+        if (size > 0)
+        {
+          RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)properties, (UInt32)size));
+        }
+      }
+    }
+
+    #ifdef COMPRESS_MT
+    if (mtMode)
+    {
+      CMyComPtr<ICompressSetCoderMt> setCoderMt;
+      decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
+      if (setCoderMt)
+      {
+        RINOK(setCoderMt->SetNumberOfThreads(numThreads));
+      }
+    }
+    #endif
+
+    #ifndef _NO_CRYPTO
+    {
+      CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+      decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
+      if (cryptoSetPassword)
+      {
+        if (getTextPassword == 0)
+          return E_FAIL;
+        CMyComBSTR password;
+        RINOK(getTextPassword->CryptoGetTextPassword(&password));
+        CByteBuffer buffer;
+        UString unicodePassword(password);
+        const UInt32 sizeInBytes = unicodePassword.Length() * 2;
+        buffer.SetCapacity(sizeInBytes);
+        for (int i = 0; i < unicodePassword.Length(); i++)
+        {
+          wchar_t c = unicodePassword[i];
+          ((Byte *)buffer)[i * 2] = (Byte)c;
+          ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
+        }
+        RINOK(cryptoSetPassword->CryptoSetPassword(
+          (const Byte *)buffer, sizeInBytes));
+      }
+    }
+    #endif
+
+    coderIndex++;
+    
+    UInt32 numInStreams = (UInt32)coderInfo.NumInStreams;
+    UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams;
+    CRecordVector<const UInt64 *> packSizesPointers;
+    CRecordVector<const UInt64 *> unPackSizesPointers;
+    packSizesPointers.Reserve(numInStreams);
+    unPackSizesPointers.Reserve(numOutStreams);
+    UInt32 j;
+    for (j = 0; j < numOutStreams; j++, unPackStreamIndex++)
+      unPackSizesPointers.Add(&folderInfo.UnPackSizes[unPackStreamIndex]);
+    
+    for (j = 0; j < numInStreams; j++, packStreamIndex++)
+    {
+      int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex);
+      if (bindPairIndex >= 0)
+        packSizesPointers.Add(
+        &folderInfo.UnPackSizes[(UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]);
+      else
+      {
+        int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex);
+        if (index < 0)
+          return E_FAIL;
+        packSizesPointers.Add(&packSizes[index]);
+      }
+    }
+    
+    _mixerCoderCommon->SetCoderInfo(i, 
+        &packSizesPointers.Front(), 
+        &unPackSizesPointers.Front());
+  }
+  UInt32 mainCoder, temp;
+  bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp);
+
+  if (_multiThread)
+    _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder);
+  /*
+  else
+    _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);;
+  */
+  
+  if (numCoders == 0)
+    return 0;
+  CRecordVector<ISequentialInStream *> inStreamPointers;
+  inStreamPointers.Reserve(inStreams.Size());
+  for (i = 0; i < inStreams.Size(); i++)
+    inStreamPointers.Add(inStreams[i]);
+  ISequentialOutStream *outStreamPointer = outStream;
+  return _mixerCoder->Code(&inStreamPointers.Front(), NULL, 
+    inStreams.Size(), &outStreamPointer, NULL, 1, compressProgress);
+}
+
+}}

+ 68 - 0
lzma/CPP/7zip/Archive/7z/7zDecode.h

@@ -0,0 +1,68 @@
+// 7zDecode.h
+
+#ifndef __7Z_DECODE_H
+#define __7Z_DECODE_H
+
+#include "../../IStream.h"
+#include "../../IPassword.h"
+
+#include "../Common/CoderMixer2.h"
+#include "../Common/CoderMixer2MT.h"
+#ifdef _ST_MODE
+#include "../Common/CoderMixer2ST.h"
+#endif
+
+#include "../../Common/CreateCoder.h"
+
+#include "7zItem.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CBindInfoEx: public NCoderMixer::CBindInfo
+{
+  CRecordVector<CMethodId> CoderMethodIDs;
+  void Clear()
+  {
+    CBindInfo::Clear();
+    CoderMethodIDs.Clear();
+  }
+};
+
+class CDecoder
+{
+  bool _bindInfoExPrevIsDefined;
+  CBindInfoEx _bindInfoExPrev;
+  
+  bool _multiThread;
+  #ifdef _ST_MODE
+  NCoderMixer::CCoderMixer2ST *_mixerCoderSTSpec;
+  #endif
+  NCoderMixer::CCoderMixer2MT *_mixerCoderMTSpec;
+  NCoderMixer::CCoderMixer2 *_mixerCoderCommon;
+  
+  CMyComPtr<ICompressCoder2> _mixerCoder;
+  CObjectVector<CMyComPtr<IUnknown> > _decoders;
+  // CObjectVector<CMyComPtr<ICompressCoder2> > _decoders2;
+public:
+  CDecoder(bool multiThread);
+  HRESULT Decode(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      IInStream *inStream,
+      UInt64 startPos,
+      const UInt64 *packSizes,
+      const CFolder &folder, 
+      ISequentialOutStream *outStream,
+      ICompressProgressInfo *compressProgress
+      #ifndef _NO_CRYPTO
+      , ICryptoGetTextPassword *getTextPasswordSpec
+      #endif
+      #ifdef COMPRESS_MT
+      , bool mtMode, UInt32 numThreads
+      #endif
+      );
+};
+
+}}
+
+#endif

+ 453 - 0
lzma/CPP/7zip/Archive/7z/7zEncode.cpp

@@ -0,0 +1,453 @@
+// Encode.cpp
+
+#include "StdAfx.h"
+
+#include "7zEncode.h"
+#include "7zSpecStream.h"
+
+#include "../../IPassword.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/InOutTempBuffer.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/CreateCoder.h"
+#include "../../Common/FilterCoder.h"
+
+static const UInt64 k_AES = 0x06F10701;
+static const UInt64 k_BCJ  = 0x03030103;
+static const UInt64 k_BCJ2 = 0x0303011B;
+
+namespace NArchive {
+namespace N7z {
+
+static void ConvertBindInfoToFolderItemInfo(const NCoderMixer::CBindInfo &bindInfo,
+    const CRecordVector<CMethodId> decompressionMethods,
+    CFolder &folder)
+{
+  folder.Coders.Clear();
+  // bindInfo.CoderMethodIDs.Clear();
+  // folder.OutStreams.Clear();
+  folder.PackStreams.Clear();
+  folder.BindPairs.Clear();
+  int i;
+  for (i = 0; i < bindInfo.BindPairs.Size(); i++)
+  {
+    CBindPair bindPair;
+    bindPair.InIndex = bindInfo.BindPairs[i].InIndex;
+    bindPair.OutIndex = bindInfo.BindPairs[i].OutIndex;
+    folder.BindPairs.Add(bindPair);
+  }
+  for (i = 0; i < bindInfo.Coders.Size(); i++)
+  {
+    CCoderInfo coderInfo;
+    const NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i];
+    coderInfo.NumInStreams = coderStreamsInfo.NumInStreams;
+    coderInfo.NumOutStreams = coderStreamsInfo.NumOutStreams;
+    coderInfo.MethodID = decompressionMethods[i];
+    folder.Coders.Add(coderInfo);
+  }
+  for (i = 0; i < bindInfo.InStreams.Size(); i++)
+    folder.PackStreams.Add(bindInfo.InStreams[i]);
+}
+
+HRESULT CEncoder::CreateMixerCoder(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    const UInt64 *inSizeForReduce)
+{
+  _mixerCoderSpec = new NCoderMixer::CCoderMixer2MT;
+  _mixerCoder = _mixerCoderSpec;
+  RINOK(_mixerCoderSpec->SetBindInfo(_bindInfo));
+  for (int i = 0; i < _options.Methods.Size(); i++)
+  {
+    const CMethodFull &methodFull = _options.Methods[i];
+    _codersInfo.Add(CCoderInfo());
+    CCoderInfo &encodingInfo = _codersInfo.Back();
+    encodingInfo.MethodID = methodFull.Id;
+    CMyComPtr<ICompressCoder> encoder;
+    CMyComPtr<ICompressCoder2> encoder2;
+    
+
+    RINOK(CreateCoder(
+        EXTERNAL_CODECS_LOC_VARS
+        methodFull.Id, encoder, encoder2, true));
+
+    if (!encoder && !encoder2)
+      return E_FAIL;
+
+    CMyComPtr<IUnknown> encoderCommon = encoder ? (IUnknown *)encoder : (IUnknown *)encoder2;
+   
+    #ifdef COMPRESS_MT
+    {
+      CMyComPtr<ICompressSetCoderMt> setCoderMt;
+      encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
+      if (setCoderMt)
+      {
+        RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads));
+      }
+    }
+    #endif
+        
+
+    RINOK(SetMethodProperties(methodFull, inSizeForReduce, encoderCommon));
+
+    /*
+    CMyComPtr<ICryptoResetSalt> resetSalt;
+    encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt);
+    if (resetSalt != NULL)
+    {
+      resetSalt->ResetSalt();
+    }
+    */
+
+    #ifdef EXTERNAL_CODECS
+    CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+    encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+    if (setCompressCodecsInfo)
+    {
+      RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo));
+    }
+    #endif
+    
+    CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+    encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
+
+    if (cryptoSetPassword)
+    {
+      CByteBuffer buffer;
+      const UInt32 sizeInBytes = _options.Password.Length() * 2;
+      buffer.SetCapacity(sizeInBytes);
+      for (int i = 0; i < _options.Password.Length(); i++)
+      {
+        wchar_t c = _options.Password[i];
+        ((Byte *)buffer)[i * 2] = (Byte)c;
+        ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
+      }
+      RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInBytes));
+    }
+
+    if (encoder)
+      _mixerCoderSpec->AddCoder(encoder);
+    else
+      _mixerCoderSpec->AddCoder2(encoder2);
+  }
+  return S_OK;
+}
+
+HRESULT CEncoder::Encode(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    ISequentialInStream *inStream,
+    const UInt64 *inStreamSize, const UInt64 *inSizeForReduce,
+    CFolder &folderItem,
+    ISequentialOutStream *outStream,
+    CRecordVector<UInt64> &packSizes,
+    ICompressProgressInfo *compressProgress)
+{
+  RINOK(EncoderConstr());
+
+  if (_mixerCoderSpec == NULL)
+  {
+    RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce));
+  }
+  _mixerCoderSpec->ReInit();
+  // _mixerCoderSpec->SetCoderInfo(0, NULL, NULL, progress);
+
+  CObjectVector<CInOutTempBuffer> inOutTempBuffers;
+  CObjectVector<CSequentialOutTempBufferImp *> tempBufferSpecs;
+  CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;
+  int numMethods = _bindInfo.Coders.Size();
+  int i;
+  for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+  {
+    inOutTempBuffers.Add(CInOutTempBuffer());
+    inOutTempBuffers.Back().Create();
+    inOutTempBuffers.Back().InitWriting();
+  }
+  for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+  {
+    CSequentialOutTempBufferImp *tempBufferSpec = 
+        new CSequentialOutTempBufferImp;
+    CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec;
+    tempBufferSpec->Init(&inOutTempBuffers[i - 1]);
+    tempBuffers.Add(tempBuffer);
+    tempBufferSpecs.Add(tempBufferSpec);
+  }
+
+  for (i = 0; i < numMethods; i++)
+    _mixerCoderSpec->SetCoderInfo(i, NULL, NULL);
+
+  if (_bindInfo.InStreams.IsEmpty())
+    return E_FAIL;
+  UInt32 mainCoderIndex, mainStreamIndex;
+  _bindInfo.FindInStream(_bindInfo.InStreams[0], mainCoderIndex, mainStreamIndex);
+  
+  if (inStreamSize != NULL)
+  {
+    CRecordVector<const UInt64 *> sizePointers;
+    for (UInt32 i = 0; i < _bindInfo.Coders[mainCoderIndex].NumInStreams; i++)
+      if (i == mainStreamIndex)
+        sizePointers.Add(inStreamSize);
+      else
+        sizePointers.Add(NULL);
+    _mixerCoderSpec->SetCoderInfo(mainCoderIndex, &sizePointers.Front(), NULL);
+  }
+
+  
+  // UInt64 outStreamStartPos;
+  // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &outStreamStartPos));
+  
+  CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = 
+      new CSequentialInStreamSizeCount2;
+  CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
+  CSequentialOutStreamSizeCount *outStreamSizeCountSpec = 
+      new CSequentialOutStreamSizeCount;
+  CMyComPtr<ISequentialOutStream> outStreamSizeCount = outStreamSizeCountSpec;
+
+  inStreamSizeCountSpec->Init(inStream);
+  outStreamSizeCountSpec->SetStream(outStream);
+  outStreamSizeCountSpec->Init();
+
+  CRecordVector<ISequentialInStream *> inStreamPointers;
+  CRecordVector<ISequentialOutStream *> outStreamPointers;
+  inStreamPointers.Add(inStreamSizeCount);
+  outStreamPointers.Add(outStreamSizeCount);
+  for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+    outStreamPointers.Add(tempBuffers[i - 1]);
+
+  for (i = 0; i < _codersInfo.Size(); i++)
+  {
+    CCoderInfo &encodingInfo = _codersInfo[i];
+    
+    CMyComPtr<ICryptoResetInitVector> resetInitVector;
+    _mixerCoderSpec->_coders[i].QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector);
+    if (resetInitVector != NULL)
+    {
+      resetInitVector->ResetInitVector();
+    }
+
+    CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
+    _mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
+    if (writeCoderProperties != NULL)
+    {
+      CSequentialOutStreamImp *outStreamSpec = new CSequentialOutStreamImp;
+      CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+      outStreamSpec->Init();
+      writeCoderProperties->WriteCoderProperties(outStream);
+      size_t size = outStreamSpec->GetSize();
+      encodingInfo.Properties.SetCapacity(size);
+      memmove(encodingInfo.Properties, outStreamSpec->GetBuffer(), size);
+    }
+  }
+
+  UInt32 progressIndex = mainCoderIndex;
+
+  for (i = 0; i < _codersInfo.Size(); i++)
+  {
+    const CCoderInfo &e = _codersInfo[i];
+    if ((e.MethodID == k_BCJ || e.MethodID == k_BCJ2) && i + 1 < _codersInfo.Size())
+      progressIndex = i + 1;
+  }
+
+  _mixerCoderSpec->SetProgressCoderIndex(progressIndex);
+  
+  RINOK(_mixerCoder->Code(&inStreamPointers.Front(), NULL, 1,
+    &outStreamPointers.Front(), NULL, outStreamPointers.Size(), compressProgress));
+  
+  ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods,
+      folderItem);
+  
+  packSizes.Add(outStreamSizeCountSpec->GetSize());
+  
+  for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+  {
+    CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1];
+    inOutTempBuffer.FlushWrite();
+    inOutTempBuffer.InitReading();
+    inOutTempBuffer.WriteToStream(outStream);
+    packSizes.Add(inOutTempBuffer.GetDataSize());
+  }
+  
+  for (i = 0; i < (int)_bindReverseConverter->NumSrcInStreams; i++)
+  {
+    int binder = _bindInfo.FindBinderForInStream(
+        _bindReverseConverter->DestOutToSrcInMap[i]);
+    UInt64 streamSize;
+    if (binder < 0)
+      streamSize = inStreamSizeCountSpec->GetSize();
+    else
+      streamSize = _mixerCoderSpec->GetWriteProcessedSize(binder);
+    folderItem.UnPackSizes.Add(streamSize);
+  }
+  for (i = numMethods - 1; i >= 0; i--)
+    folderItem.Coders[numMethods - 1 - i].Properties = _codersInfo[i].Properties;
+  return S_OK;
+}
+
+
+CEncoder::CEncoder(const CCompressionMethodMode &options):
+  _bindReverseConverter(0),
+  _constructed(false)
+{
+  if (options.IsEmpty())
+    throw 1;
+
+  _options = options;
+  _mixerCoderSpec = NULL;
+}
+
+HRESULT CEncoder::EncoderConstr()
+{
+  if (_constructed)
+    return S_OK;
+  if (_options.Methods.IsEmpty())
+  {
+    // it has only password method;
+    if (!_options.PasswordIsDefined)
+      throw 1;
+    if (!_options.Binds.IsEmpty())
+      throw 1;
+    NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+    CMethodFull method;
+    
+    method.NumInStreams = 1;
+    method.NumOutStreams = 1;
+    coderStreamsInfo.NumInStreams = 1;
+    coderStreamsInfo.NumOutStreams = 1;
+    method.Id = k_AES;
+    
+    _options.Methods.Add(method);
+    _bindInfo.Coders.Add(coderStreamsInfo);
+  
+    _bindInfo.InStreams.Add(0);
+    _bindInfo.OutStreams.Add(0);
+  }
+  else
+  {
+
+  UInt32 numInStreams = 0, numOutStreams = 0;
+  int i;
+  for (i = 0; i < _options.Methods.Size(); i++)
+  {
+    const CMethodFull &methodFull = _options.Methods[i];
+    NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+    coderStreamsInfo.NumInStreams = methodFull.NumOutStreams;
+    coderStreamsInfo.NumOutStreams = methodFull.NumInStreams;
+    if (_options.Binds.IsEmpty())
+    {
+      if (i < _options.Methods.Size() - 1)
+      {
+        NCoderMixer::CBindPair bindPair;
+        bindPair.InIndex = numInStreams + coderStreamsInfo.NumInStreams;
+        bindPair.OutIndex = numOutStreams;
+        _bindInfo.BindPairs.Add(bindPair);
+      }
+      else
+        _bindInfo.OutStreams.Insert(0, numOutStreams);
+      for (UInt32 j = 1; j < coderStreamsInfo.NumOutStreams; j++)
+        _bindInfo.OutStreams.Add(numOutStreams + j);
+    }
+    
+    numInStreams += coderStreamsInfo.NumInStreams;
+    numOutStreams += coderStreamsInfo.NumOutStreams;
+
+    _bindInfo.Coders.Add(coderStreamsInfo);
+  }
+
+  if (!_options.Binds.IsEmpty())
+  {
+    for (i = 0; i < _options.Binds.Size(); i++)
+    {
+      NCoderMixer::CBindPair bindPair;
+      const CBind &bind = _options.Binds[i];
+      bindPair.InIndex = _bindInfo.GetCoderInStreamIndex(bind.InCoder) + bind.InStream;
+      bindPair.OutIndex = _bindInfo.GetCoderOutStreamIndex(bind.OutCoder) + bind.OutStream;
+      _bindInfo.BindPairs.Add(bindPair);
+    }
+    for (i = 0; i < (int)numOutStreams; i++)
+      if (_bindInfo.FindBinderForOutStream(i) == -1)
+        _bindInfo.OutStreams.Add(i);
+  }
+
+  for (i = 0; i < (int)numInStreams; i++)
+    if (_bindInfo.FindBinderForInStream(i) == -1)
+      _bindInfo.InStreams.Add(i);
+
+  if (_bindInfo.InStreams.IsEmpty())
+    throw 1; // this is error
+
+  // Make main stream first in list
+  int inIndex = _bindInfo.InStreams[0];
+  for (;;)
+  {
+    UInt32 coderIndex, coderStreamIndex;
+    _bindInfo.FindInStream(inIndex, coderIndex, coderStreamIndex);
+    UInt32 outIndex = _bindInfo.GetCoderOutStreamIndex(coderIndex);
+    int binder = _bindInfo.FindBinderForOutStream(outIndex);
+    if (binder >= 0)
+    {
+      inIndex = _bindInfo.BindPairs[binder].InIndex;
+      continue;
+    }
+    for (i = 0; i < _bindInfo.OutStreams.Size(); i++)
+      if (_bindInfo.OutStreams[i] == outIndex)
+      {
+        _bindInfo.OutStreams.Delete(i);
+        _bindInfo.OutStreams.Insert(0, outIndex);
+        break;
+      }
+    break;
+  }
+
+  if (_options.PasswordIsDefined)
+  {
+    int numCryptoStreams = _bindInfo.OutStreams.Size();
+
+    for (i = 0; i < numCryptoStreams; i++)
+    {
+      NCoderMixer::CBindPair bindPair;
+      bindPair.InIndex = numInStreams + i;
+      bindPair.OutIndex = _bindInfo.OutStreams[i];
+      _bindInfo.BindPairs.Add(bindPair);
+    }
+    _bindInfo.OutStreams.Clear();
+
+    /*
+    if (numCryptoStreams == 0)
+      numCryptoStreams = 1;
+    */
+
+    for (i = 0; i < numCryptoStreams; i++)
+    {
+      NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+      CMethodFull method;
+      method.NumInStreams = 1;
+      method.NumOutStreams = 1;
+      coderStreamsInfo.NumInStreams = method.NumOutStreams;
+      coderStreamsInfo.NumOutStreams = method.NumInStreams;
+      method.Id = k_AES;
+
+      _options.Methods.Add(method);
+      _bindInfo.Coders.Add(coderStreamsInfo);
+      _bindInfo.OutStreams.Add(numOutStreams + i);
+    }
+  }
+
+  }
+
+  for (int i = _options.Methods.Size() - 1; i >= 0; i--)
+  {
+    const CMethodFull &methodFull = _options.Methods[i];
+    _decompressionMethods.Add(methodFull.Id);
+  }
+
+  _bindReverseConverter = new NCoderMixer::CBindReverseConverter(_bindInfo);
+  _bindReverseConverter->CreateReverseBindInfo(_decompressBindInfo);
+  _constructed = true;
+  return S_OK;
+}
+
+CEncoder::~CEncoder()
+{
+  delete _bindReverseConverter;
+}
+
+}}

+ 55 - 0
lzma/CPP/7zip/Archive/7z/7zEncode.h

@@ -0,0 +1,55 @@
+// 7zEncode.h
+
+#ifndef __7Z_ENCODE_H
+#define __7Z_ENCODE_H
+
+// #include "../../Common/StreamObjects.h"
+
+#include "7zCompressionMode.h"
+
+#include "../Common/CoderMixer2.h"
+#include "../Common/CoderMixer2MT.h"
+#ifdef _ST_MODE
+#include "../Common/CoderMixer2ST.h"
+#endif
+#include "7zItem.h"
+
+#include "../../Common/CreateCoder.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CEncoder
+{
+  NCoderMixer::CCoderMixer2MT *_mixerCoderSpec;
+  CMyComPtr<ICompressCoder2> _mixerCoder;
+
+  CObjectVector<CCoderInfo> _codersInfo;
+
+  CCompressionMethodMode _options;
+  NCoderMixer::CBindInfo _bindInfo;
+  NCoderMixer::CBindInfo _decompressBindInfo;
+  NCoderMixer::CBindReverseConverter *_bindReverseConverter;
+  CRecordVector<CMethodId> _decompressionMethods;
+
+  HRESULT CreateMixerCoder(DECL_EXTERNAL_CODECS_LOC_VARS
+      const UInt64 *inSizeForReduce);
+
+  bool _constructed;
+public:
+  CEncoder(const CCompressionMethodMode &options);
+  ~CEncoder();
+  HRESULT EncoderConstr();
+  HRESULT Encode(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      ISequentialInStream *inStream,
+      const UInt64 *inStreamSize, const UInt64 *inSizeForReduce,
+      CFolder &folderItem,
+      ISequentialOutStream *outStream,
+      CRecordVector<UInt64> &packSizes,
+      ICompressProgressInfo *compressProgress);
+};
+
+}}
+
+#endif

+ 269 - 0
lzma/CPP/7zip/Archive/7z/7zExtract.cpp

@@ -0,0 +1,269 @@
+// 7zExtract.cpp
+
+#include "StdAfx.h"
+
+#include "7zHandler.h"
+#include "7zFolderOutStream.h"
+#include "7zDecode.h"
+// #include "7z1Decode.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/LimitedStreams.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CExtractFolderInfo
+{
+  #ifdef _7Z_VOL
+  int VolumeIndex;
+  #endif
+  CNum FileIndex;
+  CNum FolderIndex;
+  CBoolVector ExtractStatuses;
+  UInt64 UnPackSize;
+  CExtractFolderInfo(
+    #ifdef _7Z_VOL
+    int volumeIndex, 
+    #endif
+    CNum fileIndex, CNum folderIndex): 
+    #ifdef _7Z_VOL
+    VolumeIndex(volumeIndex),
+    #endif
+    FileIndex(fileIndex),
+    FolderIndex(folderIndex), 
+    UnPackSize(0) 
+  {
+    if (fileIndex != kNumNoIndex)
+    {
+      ExtractStatuses.Reserve(1);
+      ExtractStatuses.Add(true);
+    }
+  };
+};
+
+STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
+    Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec)
+{
+  COM_TRY_BEGIN
+  bool testMode = (testModeSpec != 0);
+  CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
+  UInt64 importantTotalUnPacked = 0;
+
+  bool allFilesMode = (numItems == UInt32(-1));
+  if (allFilesMode)
+    numItems = 
+    #ifdef _7Z_VOL
+    _refs.Size();
+    #else
+    _database.Files.Size();
+    #endif
+
+  if(numItems == 0)
+    return S_OK;
+
+  /*
+  if(_volumes.Size() != 1)
+    return E_FAIL;
+  const CVolume &volume = _volumes.Front();
+  const CArchiveDatabaseEx &_database = volume.Database;
+  IInStream *_inStream = volume.Stream;
+  */
+  
+  CObjectVector<CExtractFolderInfo> extractFolderInfoVector;
+  for(UInt32 ii = 0; ii < numItems; ii++)
+  {
+    // UInt32 fileIndex = allFilesMode ? indexIndex : indices[indexIndex];
+    UInt32 ref2Index = allFilesMode ? ii : indices[ii];
+    // const CRef2 &ref2 = _refs[ref2Index];
+
+    // for(UInt32 ri = 0; ri < ref2.Refs.Size(); ri++)
+    {
+      #ifdef _7Z_VOL
+      // const CRef &ref = ref2.Refs[ri];
+      const CRef &ref = _refs[ref2Index];
+
+      int volumeIndex = ref.VolumeIndex;
+      const CVolume &volume = _volumes[volumeIndex];
+      const CArchiveDatabaseEx &database = volume.Database;
+      UInt32 fileIndex = ref.ItemIndex;
+      #else
+      const CArchiveDatabaseEx &database = _database;
+      UInt32 fileIndex = ref2Index;
+      #endif
+
+      CNum folderIndex = database.FileIndexToFolderIndexMap[fileIndex];
+      if (folderIndex == kNumNoIndex)
+      {
+        extractFolderInfoVector.Add(CExtractFolderInfo(
+            #ifdef _7Z_VOL
+            volumeIndex, 
+            #endif
+            fileIndex, kNumNoIndex));
+        continue;
+      }
+      if (extractFolderInfoVector.IsEmpty() || 
+        folderIndex != extractFolderInfoVector.Back().FolderIndex 
+        #ifdef _7Z_VOL
+        || volumeIndex != extractFolderInfoVector.Back().VolumeIndex
+        #endif
+        )
+      {
+        extractFolderInfoVector.Add(CExtractFolderInfo(
+            #ifdef _7Z_VOL
+            volumeIndex, 
+            #endif
+            kNumNoIndex, folderIndex));
+        const CFolder &folderInfo = database.Folders[folderIndex];
+        UInt64 unPackSize = folderInfo.GetUnPackSize();
+        importantTotalUnPacked += unPackSize;
+        extractFolderInfoVector.Back().UnPackSize = unPackSize;
+      }
+      
+      CExtractFolderInfo &efi = extractFolderInfoVector.Back();
+      
+      // const CFolderInfo &folderInfo = m_dam_Folders[folderIndex];
+      CNum startIndex = database.FolderStartFileIndex[folderIndex];
+      for (CNum index = efi.ExtractStatuses.Size();
+          index <= fileIndex - startIndex; index++)
+      {
+        // UInt64 unPackSize = _database.Files[startIndex + index].UnPackSize;
+        // Count partial_folder_size
+        // efi.UnPackSize += unPackSize;
+        // importantTotalUnPacked += unPackSize;
+        efi.ExtractStatuses.Add(index == fileIndex - startIndex);
+      }
+    }
+  }
+
+  extractCallback->SetTotal(importantTotalUnPacked);
+
+  CDecoder decoder(
+    #ifdef _ST_MODE
+    false
+    #else
+    true
+    #endif
+    );
+  // CDecoder1 decoder;
+
+  UInt64 currentTotalPacked = 0;
+  UInt64 currentTotalUnPacked = 0;
+  UInt64 totalFolderUnPacked;
+  UInt64 totalFolderPacked;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  for(int i = 0; i < extractFolderInfoVector.Size(); i++, 
+      currentTotalUnPacked += totalFolderUnPacked,
+      currentTotalPacked += totalFolderPacked)
+  {
+    lps->OutSize = currentTotalUnPacked;
+    lps->InSize = currentTotalPacked;
+    RINOK(lps->SetCur());
+    
+    const CExtractFolderInfo &efi = extractFolderInfoVector[i];
+    totalFolderUnPacked = efi.UnPackSize;
+
+    totalFolderPacked = 0;
+
+    CFolderOutStream *folderOutStream = new CFolderOutStream;
+    CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
+
+    #ifdef _7Z_VOL
+    const CVolume &volume = _volumes[efi.VolumeIndex];
+    const CArchiveDatabaseEx &database = volume.Database;
+    #else
+    const CArchiveDatabaseEx &database = _database;
+    #endif
+
+    CNum startIndex;
+    if (efi.FileIndex != kNumNoIndex)
+      startIndex = efi.FileIndex;
+    else
+      startIndex = database.FolderStartFileIndex[efi.FolderIndex];
+
+
+    HRESULT result = folderOutStream->Init(&database, 
+        #ifdef _7Z_VOL
+        volume.StartRef2Index, 
+        #else
+        0,
+        #endif
+        startIndex, 
+        &efi.ExtractStatuses, extractCallback, testMode, _crcSize != 0);
+
+    RINOK(result);
+
+    if (efi.FileIndex != kNumNoIndex)
+      continue;
+
+    CNum folderIndex = efi.FolderIndex;
+    const CFolder &folderInfo = database.Folders[folderIndex];
+
+    totalFolderPacked = _database.GetFolderFullPackSize(folderIndex);
+
+    CNum packStreamIndex = database.FolderStartPackStreamIndex[folderIndex];
+    UInt64 folderStartPackPos = database.GetFolderStreamPos(folderIndex, 0);
+
+    #ifndef _NO_CRYPTO
+    CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+    if (extractCallback)
+      extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
+    #endif
+
+    try
+    {
+      HRESULT result = decoder.Decode(
+          EXTERNAL_CODECS_VARS
+          #ifdef _7Z_VOL
+          volume.Stream,
+          #else
+          _inStream,
+          #endif
+          folderStartPackPos, 
+          &database.PackSizes[packStreamIndex],
+          folderInfo,
+          outStream,
+          progress
+          #ifndef _NO_CRYPTO
+          , getTextPassword
+          #endif
+          #ifdef COMPRESS_MT
+          , true, _numThreads
+          #endif
+          );
+
+      if (result == S_FALSE)
+      {
+        RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
+        continue;
+      }
+      if (result == E_NOTIMPL)
+      {
+        RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
+        continue;
+      }
+      if (result != S_OK)
+        return result;
+      if (folderOutStream->WasWritingFinished() != S_OK)
+      {
+        RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
+        continue;
+      }
+    }
+    catch(...)
+    {
+      RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
+      continue;
+    }
+  }
+  return S_OK;
+  COM_TRY_END
+}
+
+}}

+ 130 - 0
lzma/CPP/7zip/Archive/7z/7zFolderInStream.cpp

@@ -0,0 +1,130 @@
+// 7zFolderInStream.cpp
+
+#include "StdAfx.h"
+
+#include "7zFolderInStream.h"
+
+namespace NArchive {
+namespace N7z {
+
+CFolderInStream::CFolderInStream()
+{
+  _inStreamWithHashSpec = new CSequentialInStreamWithCRC;
+  _inStreamWithHash = _inStreamWithHashSpec;
+}
+
+void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback, 
+    const UInt32 *fileIndices, UInt32 numFiles)
+{
+  _updateCallback = updateCallback;
+  _numFiles = numFiles;
+  _fileIndex = 0;
+  _fileIndices = fileIndices;
+  Processed.Clear();
+  CRCs.Clear();
+  Sizes.Clear();
+  _fileIsOpen = false;
+  _currentSizeIsDefined = false;
+}
+
+HRESULT CFolderInStream::OpenStream()
+{
+  _filePos = 0;
+  while (_fileIndex < _numFiles)
+  {
+    _currentSizeIsDefined = false;
+    CMyComPtr<ISequentialInStream> stream;
+    HRESULT result = _updateCallback->GetStream(_fileIndices[_fileIndex], &stream);
+    if (result != S_OK && result != S_FALSE)
+      return result;
+    _fileIndex++;
+    _inStreamWithHashSpec->SetStream(stream);
+    _inStreamWithHashSpec->Init();
+    if (!stream)
+    {
+      RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+      Sizes.Add(0);
+      Processed.Add(result == S_OK);
+      AddDigest();
+      continue;
+    }
+    CMyComPtr<IStreamGetSize> streamGetSize;
+    if (stream.QueryInterface(IID_IStreamGetSize, &streamGetSize) == S_OK)
+    {
+      if(streamGetSize)
+      {
+        _currentSizeIsDefined = true;
+        RINOK(streamGetSize->GetSize(&_currentSize));
+      }
+    }
+
+    _fileIsOpen = true;
+    return S_OK;
+  }
+  return S_OK;
+}
+
+void CFolderInStream::AddDigest()
+{
+  CRCs.Add(_inStreamWithHashSpec->GetCRC());
+}
+
+HRESULT CFolderInStream::CloseStream()
+{
+  RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+  _inStreamWithHashSpec->ReleaseStream();
+  _fileIsOpen = false;
+  Processed.Add(true);
+  Sizes.Add(_filePos);
+  AddDigest();
+  return S_OK;
+}
+
+STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  UInt32 realProcessedSize = 0;
+  while ((_fileIndex < _numFiles || _fileIsOpen) && size > 0)
+  {
+    if (_fileIsOpen)
+    {
+      UInt32 localProcessedSize;
+      RINOK(_inStreamWithHash->Read(
+          ((Byte *)data) + realProcessedSize, size, &localProcessedSize));
+      if (localProcessedSize == 0)
+      {
+        RINOK(CloseStream());
+        continue;
+      }
+      realProcessedSize += localProcessedSize;
+      _filePos += localProcessedSize;
+      size -= localProcessedSize;
+      break;
+    }
+    else
+    {
+      RINOK(OpenStream());
+    }
+  }
+  if (processedSize != 0)
+    *processedSize = realProcessedSize;
+  return S_OK;
+}
+
+STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
+{
+  *value = 0;
+  int subStreamIndex = (int)subStream;
+  if (subStreamIndex < 0 || subStream > Sizes.Size())
+    return E_FAIL;
+  if (subStreamIndex < Sizes.Size())
+  {
+    *value= Sizes[subStreamIndex];
+    return S_OK;
+  }
+  if (!_currentSizeIsDefined)
+    return S_FALSE;
+  *value = _currentSize;
+  return S_OK;
+}
+
+}}

+ 66 - 0
lzma/CPP/7zip/Archive/7z/7zFolderInStream.h

@@ -0,0 +1,66 @@
+// 7z/FolderInStream.h
+
+#ifndef __7Z_FOLDERINSTREAM_H
+#define __7Z_FOLDERINSTREAM_H
+
+#include "7zItem.h"
+#include "7zHeader.h"
+
+#include "../IArchive.h"
+#include "../Common/InStreamWithCRC.h"
+#include "../../IStream.h"
+#include "../../ICoder.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CFolderInStream: 
+  public ISequentialInStream,
+  public ICompressGetSubStreamSize,
+  public CMyUnknownImp
+{
+public:
+
+  MY_UNKNOWN_IMP1(ICompressGetSubStreamSize)
+
+  CFolderInStream();
+
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+
+  STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
+private:
+  CSequentialInStreamWithCRC *_inStreamWithHashSpec;
+  CMyComPtr<ISequentialInStream> _inStreamWithHash;
+  CMyComPtr<IArchiveUpdateCallback> _updateCallback;
+
+  bool _currentSizeIsDefined;
+  UInt64 _currentSize;
+
+  bool _fileIsOpen;
+  UInt64 _filePos;
+
+  const UInt32 *_fileIndices;
+  UInt32 _numFiles;
+  UInt32 _fileIndex;
+
+  HRESULT OpenStream();
+  HRESULT CloseStream();
+  void AddDigest();
+public:
+  void Init(IArchiveUpdateCallback *updateCallback, 
+      const UInt32 *fileIndices, UInt32 numFiles);
+  CRecordVector<bool> Processed;
+  CRecordVector<UInt32> CRCs;
+  CRecordVector<UInt64> Sizes;
+  UInt64 GetFullSize() const
+  {
+    UInt64 size = 0;
+    for (int i = 0; i < Sizes.Size(); i++)      
+      size += Sizes[i];
+    return size;
+  }
+};
+
+}}
+
+#endif

+ 165 - 0
lzma/CPP/7zip/Archive/7z/7zFolderOutStream.cpp

@@ -0,0 +1,165 @@
+// 7zFolderOutStream.cpp
+
+#include "StdAfx.h"
+
+#include "7zFolderOutStream.h"
+
+namespace NArchive {
+namespace N7z {
+
+CFolderOutStream::CFolderOutStream()
+{
+  _outStreamWithHashSpec = new COutStreamWithCRC;
+  _outStreamWithHash = _outStreamWithHashSpec;
+}
+
+HRESULT CFolderOutStream::Init(
+    const CArchiveDatabaseEx *archiveDatabase,
+    UInt32 ref2Offset,
+    UInt32 startIndex,
+    const CBoolVector *extractStatuses, 
+    IArchiveExtractCallback *extractCallback,
+    bool testMode,
+    bool checkCrc)
+{
+  _archiveDatabase = archiveDatabase;
+  _ref2Offset = ref2Offset;
+  _startIndex = startIndex;
+
+  _extractStatuses = extractStatuses;
+  _extractCallback = extractCallback;
+  _testMode = testMode;
+
+  _checkCrc = checkCrc;
+
+  _currentIndex = 0;
+  _fileIsOpen = false;
+  return WriteEmptyFiles();
+}
+
+HRESULT CFolderOutStream::OpenFile()
+{
+  Int32 askMode;
+  if((*_extractStatuses)[_currentIndex])
+    askMode = _testMode ? 
+        NArchive::NExtract::NAskMode::kTest :
+        NArchive::NExtract::NAskMode::kExtract;
+  else
+    askMode = NArchive::NExtract::NAskMode::kSkip;
+  CMyComPtr<ISequentialOutStream> realOutStream;
+
+  UInt32 index = _startIndex + _currentIndex;
+  RINOK(_extractCallback->GetStream(_ref2Offset + index, &realOutStream, askMode));
+
+  _outStreamWithHashSpec->SetStream(realOutStream);
+  _outStreamWithHashSpec->Init(_checkCrc);
+  if (askMode == NArchive::NExtract::NAskMode::kExtract &&
+      (!realOutStream)) 
+  {
+    const CFileItem &fileInfo = _archiveDatabase->Files[index];
+    if (!fileInfo.IsAnti && !fileInfo.IsDirectory)
+      askMode = NArchive::NExtract::NAskMode::kSkip;
+  }
+  return _extractCallback->PrepareOperation(askMode);
+}
+
+HRESULT CFolderOutStream::WriteEmptyFiles()
+{
+  for(;_currentIndex < _extractStatuses->Size(); _currentIndex++)
+  {
+    UInt32 index = _startIndex + _currentIndex;
+    const CFileItem &fileInfo = _archiveDatabase->Files[index];
+    if (!fileInfo.IsAnti && !fileInfo.IsDirectory && fileInfo.UnPackSize != 0)
+      return S_OK;
+    RINOK(OpenFile());
+    RINOK(_extractCallback->SetOperationResult(
+        NArchive::NExtract::NOperationResult::kOK));
+    _outStreamWithHashSpec->ReleaseStream();
+  }
+  return S_OK;
+}
+
+STDMETHODIMP CFolderOutStream::Write(const void *data, 
+    UInt32 size, UInt32 *processedSize)
+{
+  UInt32 realProcessedSize = 0;
+  while(_currentIndex < _extractStatuses->Size())
+  {
+    if (_fileIsOpen)
+    {
+      UInt32 index = _startIndex + _currentIndex;
+      const CFileItem &fileInfo = _archiveDatabase->Files[index];
+      UInt64 fileSize = fileInfo.UnPackSize;
+      
+      UInt32 numBytesToWrite = (UInt32)MyMin(fileSize - _filePos, 
+          UInt64(size - realProcessedSize));
+      
+      UInt32 processedSizeLocal;
+      RINOK(_outStreamWithHash->Write((const Byte *)data + realProcessedSize, 
+            numBytesToWrite, &processedSizeLocal));
+
+      _filePos += processedSizeLocal;
+      realProcessedSize += processedSizeLocal;
+      if (_filePos == fileSize)
+      {
+        bool digestsAreEqual;
+        if (fileInfo.IsFileCRCDefined && _checkCrc)
+          digestsAreEqual = fileInfo.FileCRC == _outStreamWithHashSpec->GetCRC();
+        else
+          digestsAreEqual = true;
+
+        RINOK(_extractCallback->SetOperationResult(
+            digestsAreEqual ? 
+            NArchive::NExtract::NOperationResult::kOK :
+            NArchive::NExtract::NOperationResult::kCRCError));
+        _outStreamWithHashSpec->ReleaseStream();
+        _fileIsOpen = false;
+        _currentIndex++;
+      }
+      if (realProcessedSize == size)
+      {
+        if (processedSize != NULL)
+          *processedSize = realProcessedSize;
+        return WriteEmptyFiles();
+      }
+    }
+    else
+    {
+      RINOK(OpenFile());
+      _fileIsOpen = true;
+      _filePos = 0;
+    }
+  }
+  if (processedSize != NULL)
+    *processedSize = size;
+  return S_OK;
+}
+
+HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult)
+{
+  while(_currentIndex < _extractStatuses->Size())
+  {
+    if (_fileIsOpen)
+    {
+      RINOK(_extractCallback->SetOperationResult(resultEOperationResult));
+      _outStreamWithHashSpec->ReleaseStream();
+      _fileIsOpen = false;
+      _currentIndex++;
+    }
+    else
+    {
+      RINOK(OpenFile());
+      _fileIsOpen = true;
+    }
+  }
+  return S_OK;
+}
+
+HRESULT CFolderOutStream::WasWritingFinished()
+{
+  if (_currentIndex == _extractStatuses->Size())
+    return S_OK;
+  return E_FAIL;
+}
+
+}}

+ 60 - 0
lzma/CPP/7zip/Archive/7z/7zFolderOutStream.h

@@ -0,0 +1,60 @@
+// 7zFolderOutStream.h
+
+#ifndef __7Z_FOLDEROUTSTREAM_H
+#define __7Z_FOLDEROUTSTREAM_H
+
+#include "7zIn.h"
+
+#include "../../IStream.h"
+#include "../IArchive.h"
+#include "../Common/OutStreamWithCRC.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CFolderOutStream: 
+  public ISequentialOutStream,
+  public CMyUnknownImp
+{
+public:
+  MY_UNKNOWN_IMP
+  
+  CFolderOutStream();
+
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+private:
+
+  COutStreamWithCRC *_outStreamWithHashSpec;
+  CMyComPtr<ISequentialOutStream> _outStreamWithHash;
+  const CArchiveDatabaseEx *_archiveDatabase;
+  const CBoolVector *_extractStatuses;
+  UInt32 _startIndex;
+  UInt32 _ref2Offset;
+  int _currentIndex;
+  // UInt64 _currentDataPos;
+  CMyComPtr<IArchiveExtractCallback> _extractCallback;
+  bool _testMode;
+
+  bool _fileIsOpen;
+
+  bool _checkCrc;
+  UInt64 _filePos;
+
+  HRESULT OpenFile();
+  HRESULT WriteEmptyFiles();
+public:
+  HRESULT Init(
+      const CArchiveDatabaseEx *archiveDatabase,
+      UInt32 ref2Offset,
+      UInt32 startIndex,
+      const CBoolVector *extractStatuses, 
+      IArchiveExtractCallback *extractCallback,
+      bool testMode,
+      bool checkCrc);
+  HRESULT FlushCorrupted(Int32 resultEOperationResult);
+  HRESULT WasWritingFinished();
+};
+
+}}
+
+#endif

+ 793 - 0
lzma/CPP/7zip/Archive/7z/7zHandler.cpp

@@ -0,0 +1,793 @@
+// 7zHandler.cpp
+
+#include "StdAfx.h"
+
+#include "7zHandler.h"
+#include "7zProperties.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/ComTry.h"
+#include "../../../Windows/Defs.h"
+
+#include "../Common/ItemNameUtils.h"
+#ifdef _7Z_VOL
+#include "../Common/MultiStream.h"
+#endif
+
+#ifdef __7Z_SET_PROPERTIES
+#ifdef EXTRACT_ONLY
+#include "../Common/ParseProperties.h"
+#endif
+#endif
+
+#ifdef COMPRESS_MT
+#include "../../../Windows/System.h"
+#endif
+
+using namespace NWindows;
+
+extern UString ConvertMethodIdToString(UInt64 id);
+
+namespace NArchive {
+namespace N7z {
+
+CHandler::CHandler()
+{
+  _crcSize = 4;
+
+  #ifdef EXTRACT_ONLY
+  #ifdef COMPRESS_MT
+  _numThreads = NWindows::NSystem::GetNumberOfProcessors();
+  #endif
+  #else
+  Init();
+  #endif
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+  *numItems = 
+  #ifdef _7Z_VOL
+  _refs.Size();
+  #else
+  *numItems = _database.Files.Size();
+  #endif
+  return S_OK;
+}
+
+#ifdef _SFX
+
+IMP_IInArchive_ArcProps_NO
+
+STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 * /* numProperties */)
+{
+  return E_NOTIMPL;
+}
+
+STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */,     
+      BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)
+{
+  return E_NOTIMPL;
+}
+
+
+#else
+
+STATPROPSTG kArcProps[] = 
+{
+  { NULL, kpidMethod, VT_BSTR},
+  { NULL, kpidSolid, VT_BOOL},
+  { NULL, kpidNumBlocks, VT_UI4}
+};
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+  COM_TRY_BEGIN
+  NWindows::NCOM::CPropVariant prop;
+  switch(propID)
+  {
+    case kpidMethod:
+    {
+      UString resString;
+      CRecordVector<UInt64> ids;
+      int i;
+      for (i = 0; i < _database.Folders.Size(); i++)
+      {
+        const CFolder &f = _database.Folders[i];
+        for (int j = f.Coders.Size() - 1; j >= 0; j--)
+          ids.AddToUniqueSorted(f.Coders[j].MethodID);
+      }
+
+      for (i = 0; i < ids.Size(); i++)
+      {
+        UInt64 id = ids[i];
+        UString methodName;
+        /* bool methodIsKnown = */ FindMethod(EXTERNAL_CODECS_VARS id, methodName);
+        if (methodName.IsEmpty())
+          methodName = ConvertMethodIdToString(id);
+        if (!resString.IsEmpty())
+          resString += L' ';
+        resString += methodName;
+      }
+      prop = resString; 
+      break;
+    }
+    case kpidSolid: prop = _database.IsSolid(); break;
+    case kpidNumBlocks: prop = (UInt32)_database.Folders.Size(); break;
+  }
+  prop.Detach(value);
+  return S_OK;
+  COM_TRY_END
+}
+
+IMP_IInArchive_ArcProps
+
+#endif
+
+static void MySetFileTime(bool timeDefined, FILETIME unixTime, NWindows::NCOM::CPropVariant &prop)
+{
+  if (timeDefined)
+    prop = unixTime;
+}
+
+#ifndef _SFX
+
+static UString ConvertUInt32ToString(UInt32 value)
+{
+  wchar_t buffer[32];
+  ConvertUInt64ToString(value, buffer);
+  return buffer;
+}
+
+static UString GetStringForSizeValue(UInt32 value)
+{
+  for (int i = 31; i >= 0; i--)
+    if ((UInt32(1) << i) == value)
+      return ConvertUInt32ToString(i);
+  UString result;
+  if (value % (1 << 20) == 0)
+  {
+    result += ConvertUInt32ToString(value >> 20);
+    result += L"m";
+  }
+  else if (value % (1 << 10) == 0)
+  {
+    result += ConvertUInt32ToString(value >> 10);
+    result += L"k";
+  }
+  else
+  {
+    result += ConvertUInt32ToString(value);
+    result += L"b";
+  }
+  return result;
+}
+
+static const UInt64 k_Copy = 0x0;
+static const UInt64 k_LZMA  = 0x030101;
+static const UInt64 k_PPMD  = 0x030401;
+
+static wchar_t GetHex(Byte value)
+{
+  return (wchar_t)((value < 10) ? (L'0' + value) : (L'A' + (value - 10)));
+}
+static inline UString GetHex2(Byte value)
+{
+  UString result;
+  result += GetHex((Byte)(value >> 4));
+  result += GetHex((Byte)(value & 0xF));
+  return result;
+}
+
+#endif
+
+static const UInt64 k_AES  = 0x06F10701;
+
+#ifndef _SFX
+static inline UInt32 GetUInt32FromMemLE(const Byte *p)
+{
+  return p[0] | (((UInt32)p[1]) << 8) | (((UInt32)p[2]) << 16) | (((UInt32)p[3]) << 24);
+}
+#endif
+
+bool CHandler::IsEncrypted(UInt32 index2) const
+{
+  CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
+  if (folderIndex != kNumNoIndex)
+  {
+    const CFolder &folderInfo = _database.Folders[folderIndex];
+    for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
+      if (folderInfo.Coders[i].MethodID == k_AES)
+        return true;
+  }
+  return false;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID,  PROPVARIANT *value)
+{
+  COM_TRY_BEGIN
+  NWindows::NCOM::CPropVariant prop;
+  
+  /*
+  const CRef2 &ref2 = _refs[index];
+  if (ref2.Refs.IsEmpty())
+    return E_FAIL;
+  const CRef &ref = ref2.Refs.Front();
+  */
+  
+  #ifdef _7Z_VOL
+  const CRef &ref = _refs[index];
+  const CVolume &volume = _volumes[ref.VolumeIndex];
+  const CArchiveDatabaseEx &_database = volume.Database;
+  UInt32 index2 = ref.ItemIndex;
+  const CFileItem &item = _database.Files[index2];
+  #else
+  const CFileItem &item = _database.Files[index];
+  UInt32 index2 = index;
+  #endif
+
+  switch(propID)
+  {
+    case kpidPath:
+    {
+      if (!item.Name.IsEmpty())
+        prop = NItemName::GetOSName(item.Name);
+      break;
+    }
+    case kpidIsFolder:
+      prop = item.IsDirectory;
+      break;
+    case kpidSize:
+    {
+      prop = item.UnPackSize;
+      // prop = ref2.UnPackSize;
+      break;
+    }
+    case kpidPosition:
+    {
+      /*
+      if (ref2.Refs.Size() > 1)
+        prop = ref2.StartPos;
+      else
+      */
+        if (item.IsStartPosDefined)
+          prop = item.StartPos;
+      break;
+    }
+    case kpidPackedSize:
+    {
+      // prop = ref2.PackSize;
+      {
+        CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
+        if (folderIndex != kNumNoIndex)
+        {
+          if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2)
+            prop = _database.GetFolderFullPackSize(folderIndex);
+          /*
+          else
+            prop = (UInt64)0;
+          */
+        }
+        else
+          prop = (UInt64)0;
+      }
+      break;
+    }
+    case kpidLastAccessTime:
+      MySetFileTime(item.IsLastAccessTimeDefined, item.LastAccessTime, prop);
+      break;
+    case kpidCreationTime:
+      MySetFileTime(item.IsCreationTimeDefined, item.CreationTime, prop);
+      break;
+    case kpidLastWriteTime:
+      MySetFileTime(item.IsLastWriteTimeDefined, item.LastWriteTime, prop);
+      break;
+    case kpidAttributes:
+      if (item.AreAttributesDefined)
+        prop = item.Attributes;
+      break;
+    case kpidCRC:
+      if (item.IsFileCRCDefined)
+        prop = item.FileCRC;
+      break;
+    case kpidEncrypted:
+    {
+      prop = IsEncrypted(index2);
+      break;
+    }
+    #ifndef _SFX
+    case kpidMethod:
+      {
+        CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
+        if (folderIndex != kNumNoIndex)
+        {
+          const CFolder &folderInfo = _database.Folders[folderIndex];
+          UString methodsString;
+          for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
+          {
+            const CCoderInfo &coderInfo = folderInfo.Coders[i];
+            if (!methodsString.IsEmpty())
+              methodsString += L' ';
+
+            {
+              UString methodName;
+              bool methodIsKnown = FindMethod(
+                  EXTERNAL_CODECS_VARS 
+                  coderInfo.MethodID, methodName);
+
+              if (methodIsKnown)
+              {
+                methodsString += methodName;
+                if (coderInfo.MethodID == k_LZMA)
+                {
+                  if (coderInfo.Properties.GetCapacity() >= 5)
+                  {
+                    methodsString += L":";
+                    UInt32 dicSize = GetUInt32FromMemLE(
+                      ((const Byte *)coderInfo.Properties + 1));
+                    methodsString += GetStringForSizeValue(dicSize);
+                  }
+                }
+                else if (coderInfo.MethodID == k_PPMD)
+                {
+                  if (coderInfo.Properties.GetCapacity() >= 5)
+                  {
+                    Byte order = *(const Byte *)coderInfo.Properties;
+                    methodsString += L":o";
+                    methodsString += ConvertUInt32ToString(order);
+                    methodsString += L":mem";
+                    UInt32 dicSize = GetUInt32FromMemLE(
+                      ((const Byte *)coderInfo.Properties + 1));
+                    methodsString += GetStringForSizeValue(dicSize);
+                  }
+                }
+                else if (coderInfo.MethodID == k_AES)
+                {
+                  if (coderInfo.Properties.GetCapacity() >= 1)
+                  {
+                    methodsString += L":";
+                    const Byte *data = (const Byte *)coderInfo.Properties;
+                    Byte firstByte = *data++;
+                    UInt32 numCyclesPower = firstByte & 0x3F;
+                    methodsString += ConvertUInt32ToString(numCyclesPower);
+                    /*
+                    if ((firstByte & 0xC0) != 0)
+                    {
+                      methodsString += L":";
+                      return S_OK;
+                      UInt32 saltSize = (firstByte >> 7) & 1;
+                      UInt32 ivSize = (firstByte >> 6) & 1;
+                      if (coderInfo.Properties.GetCapacity() >= 2)
+                      {
+                        Byte secondByte = *data++;
+                        saltSize += (secondByte >> 4);
+                        ivSize += (secondByte & 0x0F);
+                      }
+                    }
+                    */
+                  }
+                }
+                else
+                {
+                  if (coderInfo.Properties.GetCapacity() > 0)
+                  {
+                    methodsString += L":[";
+                    for (size_t bi = 0; bi < coderInfo.Properties.GetCapacity(); bi++)
+                    {
+                      if (bi > 5 && bi + 1 < coderInfo.Properties.GetCapacity())
+                      {
+                        methodsString += L"..";
+                        break;
+                      }
+                      else
+                        methodsString += GetHex2(coderInfo.Properties[bi]);
+                    }
+                    methodsString += L"]";
+                  }
+                }
+              }
+              else
+              {
+                methodsString += ConvertMethodIdToString(coderInfo.MethodID);
+              }
+            }
+          }
+          prop = methodsString;
+        }
+      }
+      break;
+    case kpidBlock:
+      {
+        CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
+        if (folderIndex != kNumNoIndex)
+          prop = (UInt32)folderIndex;
+      }
+      break;
+    case kpidPackedSize0:
+    case kpidPackedSize1:
+    case kpidPackedSize2:
+    case kpidPackedSize3:
+    case kpidPackedSize4:
+      {
+        CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
+        if (folderIndex != kNumNoIndex)
+        {
+          const CFolder &folderInfo = _database.Folders[folderIndex];
+          if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
+              folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0))
+          {
+            prop = _database.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0);
+          }
+          else
+            prop = (UInt64)0;
+        }
+        else
+          prop = (UInt64)0;
+      }
+      break;
+    #endif
+    case kpidIsAnti:
+      prop = item.IsAnti;
+      break;
+  }
+  prop.Detach(value);
+  return S_OK;
+  COM_TRY_END
+}
+
+#ifdef _7Z_VOL
+
+static const wchar_t *kExt = L"7z";
+static const wchar_t *kAfterPart = L".7z";
+
+class CVolumeName
+{
+  bool _first;
+  UString _unchangedPart;
+  UString _changedPart;    
+  UString _afterPart;    
+public:
+  bool InitName(const UString &name)
+  {
+    _first = true;
+    int dotPos = name.ReverseFind('.');
+    UString basePart = name;
+    if (dotPos >= 0)
+    {
+      UString ext = name.Mid(dotPos + 1);
+      if (ext.CompareNoCase(kExt)==0 || 
+        ext.CompareNoCase(L"EXE") == 0)
+      {
+        _afterPart = kAfterPart;
+        basePart = name.Left(dotPos);
+      }
+    }
+
+    int numLetters = 1;
+    bool splitStyle = false;
+    if (basePart.Right(numLetters) == L"1")
+    {
+      while (numLetters < basePart.Length())
+      {
+        if (basePart[basePart.Length() - numLetters - 1] != '0')
+          break;
+        numLetters++;
+      }
+    }
+    else 
+      return false;
+    _unchangedPart = basePart.Left(basePart.Length() - numLetters);
+    _changedPart = basePart.Right(numLetters);
+    return true;
+  }
+
+  UString GetNextName()
+  {
+    UString newName; 
+    // if (_newStyle || !_first)
+    {
+      int i;
+      int numLetters = _changedPart.Length();
+      for (i = numLetters - 1; i >= 0; i--)
+      {
+        wchar_t c = _changedPart[i];
+        if (c == L'9')
+        {
+          c = L'0';
+          newName = c + newName;
+          if (i == 0)
+            newName = UString(L'1') + newName;
+          continue;
+        }
+        c++;
+        newName = UString(c) + newName;
+        i--;
+        for (; i >= 0; i--)
+          newName = _changedPart[i] + newName;
+        break;
+      }
+      _changedPart = newName;
+    }
+    _first = false;
+    return _unchangedPart + _changedPart + _afterPart;
+  }
+};
+
+#endif
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+    const UInt64 *maxCheckStartPosition, 
+    IArchiveOpenCallback *openArchiveCallback)
+{
+  COM_TRY_BEGIN
+  Close();
+  #ifndef _SFX
+  _fileInfoPopIDs.Clear();
+  #endif
+  try
+  {
+    CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
+    #ifdef _7Z_VOL
+    CVolumeName seqName;
+
+    CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+    #endif
+
+    #ifndef _NO_CRYPTO
+    CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+    if (openArchiveCallback)
+    {
+      openArchiveCallbackTemp.QueryInterface(
+          IID_ICryptoGetTextPassword, &getTextPassword);
+    }
+    #endif
+    #ifdef _7Z_VOL
+    if (openArchiveCallback)
+    {
+      openArchiveCallbackTemp.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback);
+    }
+    for (;;)
+    {
+      CMyComPtr<IInStream> inStream;
+      if (!_volumes.IsEmpty())
+      {
+        if (!openVolumeCallback)
+          break;
+        if(_volumes.Size() == 1)
+        {
+          UString baseName;
+          {
+            NCOM::CPropVariant prop;
+            RINOK(openVolumeCallback->GetProperty(kpidName, &prop));
+            if (prop.vt != VT_BSTR)
+              break;
+            baseName = prop.bstrVal;
+          }
+          seqName.InitName(baseName);
+        }
+
+        UString fullName = seqName.GetNextName();
+        HRESULT result = openVolumeCallback->GetStream(fullName, &inStream);
+        if (result == S_FALSE)
+          break;
+        if (result != S_OK)
+          return result;
+        if (!stream)
+          break;
+      }
+      else
+        inStream = stream;
+
+      CInArchive archive;
+      RINOK(archive.Open(inStream, maxCheckStartPosition));
+
+      _volumes.Add(CVolume());
+      CVolume &volume = _volumes.Back();
+      CArchiveDatabaseEx &database = volume.Database;
+      volume.Stream = inStream;
+      volume.StartRef2Index = _refs.Size();
+
+      HRESULT result = archive.ReadDatabase(database
+          #ifndef _NO_CRYPTO
+          , getTextPassword
+          #endif
+          );
+      if (result != S_OK)
+      {
+        _volumes.Clear();
+        return result;
+      }
+      database.Fill();
+      for(int i = 0; i < database.Files.Size(); i++)
+      {
+        CRef refNew;
+        refNew.VolumeIndex = _volumes.Size() - 1;
+        refNew.ItemIndex = i;
+        _refs.Add(refNew);
+        /*
+        const CFileItem &file = database.Files[i];
+        int j;
+        */
+        /*
+        for (j = _refs.Size() - 1; j >= 0; j--)
+        {
+          CRef2 &ref2 = _refs[j];
+          const CRef &ref = ref2.Refs.Back();
+          const CVolume &volume2 = _volumes[ref.VolumeIndex];
+          const CArchiveDatabaseEx &database2 = volume2.Database;
+          const CFileItem &file2 = database2.Files[ref.ItemIndex];
+          if (file2.Name.CompareNoCase(file.Name) == 0)
+          {
+            if (!file.IsStartPosDefined)
+              continue;
+            if (file.StartPos != ref2.StartPos + ref2.UnPackSize)
+              continue;
+            ref2.Refs.Add(refNew);
+            break;
+          }
+        }
+        */
+        /*
+        j = -1;
+        if (j < 0)
+        {
+          CRef2 ref2New;
+          ref2New.Refs.Add(refNew);
+          j = _refs.Add(ref2New);
+        }
+        CRef2 &ref2 = _refs[j];
+        ref2.UnPackSize += file.UnPackSize;
+        ref2.PackSize += database.GetFilePackSize(i);
+        if (ref2.Refs.Size() == 1 && file.IsStartPosDefined)
+          ref2.StartPos = file.StartPos;
+        */
+      }
+      if (database.Files.Size() != 1)
+        break;
+      const CFileItem &file = database.Files.Front();
+      if (!file.IsStartPosDefined)
+        break;
+    }
+    #else
+    CInArchive archive;
+    RINOK(archive.Open(stream, maxCheckStartPosition));
+    HRESULT result = archive.ReadDatabase(
+      EXTERNAL_CODECS_VARS
+      _database
+      #ifndef _NO_CRYPTO
+      , getTextPassword
+      #endif
+      );
+    RINOK(result);
+    _database.Fill();
+    _inStream = stream;
+    #endif
+  }
+  catch(...)
+  {
+    Close();
+    return S_FALSE;
+  }
+  // _inStream = stream;
+  #ifndef _SFX
+  FillPopIDs();
+  #endif
+  return S_OK;
+  COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+  COM_TRY_BEGIN
+  #ifdef _7Z_VOL
+  _volumes.Clear();
+  _refs.Clear();
+  #else
+  _inStream.Release();
+  _database.Clear();
+  #endif
+  return S_OK;
+  COM_TRY_END
+}
+
+#ifdef _7Z_VOL
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+  if (index != 0)
+    return E_INVALIDARG;
+  *stream = 0;
+  CMultiStream *streamSpec = new CMultiStream;
+  CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+  
+  UInt64 pos = 0;
+  const UString *fileName;
+  for (int i = 0; i < _refs.Size(); i++)
+  {
+    const CRef &ref = _refs[i];
+    const CVolume &volume = _volumes[ref.VolumeIndex];
+    const CArchiveDatabaseEx &database = volume.Database;
+    const CFileItem &file = database.Files[ref.ItemIndex];
+    if (i == 0)
+      fileName = &file.Name;
+    else
+      if (fileName->Compare(file.Name) != 0)
+        return S_FALSE;
+    if (!file.IsStartPosDefined)
+      return S_FALSE;
+    if (file.StartPos != pos)
+      return S_FALSE;
+    CNum folderIndex = database.FileIndexToFolderIndexMap[ref.ItemIndex];
+    if (folderIndex == kNumNoIndex)
+    {
+      if (file.UnPackSize != 0)
+        return E_FAIL;
+      continue;
+    }
+    if (database.NumUnPackStreamsVector[folderIndex] != 1)
+      return S_FALSE;
+    const CFolder &folder = database.Folders[folderIndex];
+    if (folder.Coders.Size() != 1)
+      return S_FALSE;
+    const CCoderInfo &coder = folder.Coders.Front();
+    if (coder.NumInStreams != 1 || coder.NumOutStreams != 1)
+      return S_FALSE;
+    if (coder.MethodID != k_Copy)
+      return S_FALSE;
+
+    pos += file.UnPackSize;
+    CMultiStream::CSubStreamInfo subStreamInfo;
+    subStreamInfo.Stream = volume.Stream;
+    subStreamInfo.Pos = database.GetFolderStreamPos(folderIndex, 0);
+    subStreamInfo.Size = file.UnPackSize;
+    streamSpec->Streams.Add(subStreamInfo);
+  }
+  streamSpec->Init();
+  *stream = streamTemp.Detach();
+  return S_OK;
+}
+#endif
+
+
+#ifdef __7Z_SET_PROPERTIES
+#ifdef EXTRACT_ONLY
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
+{
+  COM_TRY_BEGIN
+  #ifdef COMPRESS_MT
+  const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
+  _numThreads = numProcessors;
+  #endif
+
+  for (int i = 0; i < numProperties; i++)
+  {
+    UString name = names[i];
+    name.MakeUpper();
+    if (name.IsEmpty())
+      return E_INVALIDARG;
+    const PROPVARIANT &value = values[i];
+    UInt32 number;
+    int index = ParseStringToUInt32(name, number);
+    if (index == 0)
+    {
+      if(name.Left(2).CompareNoCase(L"MT") == 0)
+      {
+        #ifdef COMPRESS_MT
+        RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
+        #endif
+        continue;
+      }
+      else
+        return E_INVALIDARG;
+    }
+  }
+  return S_OK;
+  COM_TRY_END
+}  
+
+#endif
+#endif
+
+IMPL_ISetCompressCodecsInfo
+
+}}

+ 146 - 0
lzma/CPP/7zip/Archive/7z/7zHandler.h

@@ -0,0 +1,146 @@
+// 7z/Handler.h
+
+#ifndef __7Z_HANDLER_H
+#define __7Z_HANDLER_H
+
+#include "../../ICoder.h"
+#include "../IArchive.h"
+#include "7zIn.h"
+
+#include "7zCompressionMode.h"
+
+#include "../../Common/CreateCoder.h"
+
+#ifndef EXTRACT_ONLY
+#include "../Common/HandlerOut.h"
+#endif
+
+namespace NArchive {
+namespace N7z {
+
+#ifdef _7Z_VOL
+struct CRef
+{
+  int VolumeIndex;
+  int ItemIndex;
+};
+
+struct CVolume
+{
+  int StartRef2Index;
+  CMyComPtr<IInStream> Stream;
+  CArchiveDatabaseEx Database;
+};
+#endif
+
+#ifndef __7Z_SET_PROPERTIES
+
+#ifdef EXTRACT_ONLY
+#ifdef COMPRESS_MT
+#define __7Z_SET_PROPERTIES
+#endif
+#else 
+#define __7Z_SET_PROPERTIES
+#endif
+
+#endif
+
+
+class CHandler: 
+  #ifndef EXTRACT_ONLY
+  public NArchive::COutHandler,
+  #endif
+  public IInArchive,
+  #ifdef _7Z_VOL
+  public IInArchiveGetStream,
+  #endif
+  #ifdef __7Z_SET_PROPERTIES
+  public ISetProperties, 
+  #endif
+  #ifndef EXTRACT_ONLY
+  public IOutArchive, 
+  #endif
+  PUBLIC_ISetCompressCodecsInfo
+  public CMyUnknownImp
+{
+public:
+  MY_QUERYINTERFACE_BEGIN2(IInArchive)
+  #ifdef _7Z_VOL
+  MY_QUERYINTERFACE_ENTRY(IInArchiveGetStream)
+  #endif
+  #ifdef __7Z_SET_PROPERTIES
+  MY_QUERYINTERFACE_ENTRY(ISetProperties)
+  #endif
+  #ifndef EXTRACT_ONLY
+  MY_QUERYINTERFACE_ENTRY(IOutArchive)
+  #endif
+  QUERY_ENTRY_ISetCompressCodecsInfo
+  MY_QUERYINTERFACE_END
+  MY_ADDREF_RELEASE
+
+  INTERFACE_IInArchive(;)
+
+  #ifdef _7Z_VOL
+  STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);  
+  #endif
+
+  #ifdef __7Z_SET_PROPERTIES
+  STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties);
+  #endif
+
+  #ifndef EXTRACT_ONLY
+  INTERFACE_IOutArchive(;)
+  #endif
+
+  DECL_ISetCompressCodecsInfo
+
+  CHandler();
+
+private:
+  #ifdef _7Z_VOL
+  CObjectVector<CVolume> _volumes;
+  CObjectVector<CRef> _refs;
+  #else
+  CMyComPtr<IInStream> _inStream;
+  NArchive::N7z::CArchiveDatabaseEx _database;
+  #endif
+
+  #ifdef EXTRACT_ONLY
+  
+  #ifdef COMPRESS_MT
+  UInt32 _numThreads;
+  #endif
+
+  UInt32 _crcSize;
+
+  #else
+  
+  CRecordVector<CBind> _binds;
+
+  HRESULT SetPassword(CCompressionMethodMode &methodMode, IArchiveUpdateCallback *updateCallback);
+
+  HRESULT SetCompressionMethod(CCompressionMethodMode &method,
+      CObjectVector<COneMethodInfo> &methodsInfo
+      #ifdef COMPRESS_MT
+      , UInt32 numThreads
+      #endif
+      );
+
+  HRESULT SetCompressionMethod(
+      CCompressionMethodMode &method,
+      CCompressionMethodMode &headerMethod);
+
+  #endif
+
+  bool IsEncrypted(UInt32 index2) const;
+  #ifndef _SFX
+
+  CRecordVector<UInt64> _fileInfoPopIDs;
+  void FillPopIDs();
+
+  #endif
+};
+
+}}
+
+#endif

+ 464 - 0
lzma/CPP/7zip/Archive/7z/7zHandlerOut.cpp

@@ -0,0 +1,464 @@
+// 7zHandlerOut.cpp
+
+#include "StdAfx.h"
+
+#include "7zHandler.h"
+#include "7zOut.h"
+#include "7zUpdate.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/StringToInt.h"
+#include "../../IPassword.h"
+#include "../../ICoder.h"
+
+#include "../Common/ItemNameUtils.h"
+#include "../Common/ParseProperties.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace N7z {
+
+static const wchar_t *kLZMAMethodName = L"LZMA";
+static const wchar_t *kCopyMethod = L"Copy";
+static const wchar_t *kDefaultMethodName = kLZMAMethodName;
+
+static const UInt32 kLzmaAlgorithmX5 = 1;
+static const wchar_t *kLzmaMatchFinderForHeaders = L"BT2";
+static const UInt32 kDictionaryForHeaders = 1 << 20;
+static const UInt32 kNumFastBytesForHeaders = 273;
+static const UInt32 kAlgorithmForHeaders = kLzmaAlgorithmX5;
+
+static inline bool IsCopyMethod(const UString &methodName)
+  { return (methodName.CompareNoCase(kCopyMethod) == 0); }
+
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
+{
+  *type = NFileTimeType::kWindows;
+  return S_OK;
+}
+
+HRESULT CHandler::SetPassword(CCompressionMethodMode &methodMode,
+    IArchiveUpdateCallback *updateCallback)
+{
+  CMyComPtr<ICryptoGetTextPassword2> getTextPassword;
+  if (!getTextPassword)
+  {
+    CMyComPtr<IArchiveUpdateCallback> udateCallback2(updateCallback);
+    udateCallback2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword);
+  }
+  
+  if (getTextPassword)
+  {
+    CMyComBSTR password;
+    Int32 passwordIsDefined;
+    RINOK(getTextPassword->CryptoGetTextPassword2(
+        &passwordIsDefined, &password));
+    methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
+    if (methodMode.PasswordIsDefined)
+      methodMode.Password = password;
+  }
+  else
+    methodMode.PasswordIsDefined = false;
+  return S_OK;
+}
+
+HRESULT CHandler::SetCompressionMethod(
+    CCompressionMethodMode &methodMode,
+    CCompressionMethodMode &headerMethod)
+{
+  HRESULT res = SetCompressionMethod(methodMode, _methods
+  #ifdef COMPRESS_MT
+  , _numThreads
+  #endif
+  );
+  RINOK(res);
+  methodMode.Binds = _binds;
+
+  if (_compressHeaders)
+  {
+    // headerMethod.Methods.Add(methodMode.Methods.Back());
+
+    CObjectVector<COneMethodInfo> headerMethodInfoVector;
+    COneMethodInfo oneMethodInfo;
+    oneMethodInfo.MethodName = kLZMAMethodName;
+    {
+      CProp property;
+      property.Id = NCoderPropID::kMatchFinder;
+      property.Value = kLzmaMatchFinderForHeaders;
+      oneMethodInfo.Properties.Add(property);
+    }
+    {
+      CProp property;
+      property.Id = NCoderPropID::kAlgorithm;
+      property.Value = kAlgorithmForHeaders;
+      oneMethodInfo.Properties.Add(property);
+    }
+    {
+      CProp property;
+      property.Id = NCoderPropID::kNumFastBytes;
+      property.Value = UInt32(kNumFastBytesForHeaders);
+      oneMethodInfo.Properties.Add(property);
+    }
+    {
+      CProp property;
+      property.Id = NCoderPropID::kDictionarySize;
+      property.Value = UInt32(kDictionaryForHeaders);
+      oneMethodInfo.Properties.Add(property);
+    }
+    headerMethodInfoVector.Add(oneMethodInfo);
+    HRESULT res = SetCompressionMethod(headerMethod, headerMethodInfoVector
+      #ifdef COMPRESS_MT
+      ,1
+      #endif
+    );
+    RINOK(res);
+  }
+  return S_OK;
+}
+
+HRESULT CHandler::SetCompressionMethod(
+    CCompressionMethodMode &methodMode,
+    CObjectVector<COneMethodInfo> &methodsInfo
+    #ifdef COMPRESS_MT
+    , UInt32 numThreads
+    #endif
+    )
+{
+  UInt32 level = _level;
+  
+  if (methodsInfo.IsEmpty())
+  {
+    COneMethodInfo oneMethodInfo;
+    oneMethodInfo.MethodName = ((level == 0) ? kCopyMethod : kDefaultMethodName);
+    methodsInfo.Add(oneMethodInfo);
+  }
+
+  bool needSolid = false;
+  for(int i = 0; i < methodsInfo.Size(); i++)
+  {
+    COneMethodInfo &oneMethodInfo = methodsInfo[i];
+    SetCompressionMethod2(oneMethodInfo
+      #ifdef COMPRESS_MT
+      , numThreads
+      #endif
+      );
+
+    if (!IsCopyMethod(oneMethodInfo.MethodName))
+      needSolid = true;
+
+    CMethodFull methodFull;
+
+    if (!FindMethod(
+        EXTERNAL_CODECS_VARS
+        oneMethodInfo.MethodName, methodFull.Id, methodFull.NumInStreams, methodFull.NumOutStreams))
+      return E_INVALIDARG;
+    methodFull.Properties = oneMethodInfo.Properties;
+    methodMode.Methods.Add(methodFull);
+
+    if (!_numSolidBytesDefined)
+    {
+      for (int j = 0; j < methodFull.Properties.Size(); j++)
+      {
+        const CProp &prop = methodFull.Properties[j];
+        if ((prop.Id == NCoderPropID::kDictionarySize || 
+             prop.Id == NCoderPropID::kUsedMemorySize) && prop.Value.vt == VT_UI4)
+        {
+          _numSolidBytes = ((UInt64)prop.Value.ulVal) << 7;
+          const UInt64 kMinSize = (1 << 24);
+          if (_numSolidBytes < kMinSize)
+            _numSolidBytes = kMinSize;
+          _numSolidBytesDefined = true;
+          break;
+        }
+      }
+    }
+  }
+
+  if (!needSolid && !_numSolidBytesDefined)
+  {
+    _numSolidBytesDefined = true;
+    _numSolidBytes  = 0;
+  }
+  return S_OK;
+}
+
+static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, CArchiveFileTime &filetime, bool &filetimeIsDefined)
+{
+  filetimeIsDefined = false;
+  NCOM::CPropVariant propVariant;
+  RINOK(updateCallback->GetProperty(index, propID, &propVariant));
+  if (propVariant.vt == VT_FILETIME)
+  {
+    filetime = propVariant.filetime;
+    filetimeIsDefined = true;
+  }
+  else if (propVariant.vt != VT_EMPTY)
+    return E_INVALIDARG;
+  return S_OK;
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+    IArchiveUpdateCallback *updateCallback)
+{
+  COM_TRY_BEGIN
+
+  const CArchiveDatabaseEx *database = 0;
+  #ifdef _7Z_VOL
+  if(_volumes.Size() > 1)
+    return E_FAIL;
+  const CVolume *volume = 0;
+  if (_volumes.Size() == 1)
+  {
+    volume = &_volumes.Front();
+    database = &volume->Database;
+  }
+  #else
+  if (_inStream != 0)
+    database = &_database;
+  #endif
+
+  // CRecordVector<bool> compressStatuses;
+  CObjectVector<CUpdateItem> updateItems;
+  // CRecordVector<UInt32> copyIndices;
+  
+  // CMyComPtr<IUpdateCallback2> updateCallback2;
+  // updateCallback->QueryInterface(&updateCallback2);
+
+  for(UInt32 i = 0; i < numItems; i++)
+  {
+    Int32 newData;
+    Int32 newProperties;
+    UInt32 indexInArchive;
+    if (!updateCallback)
+      return E_FAIL;
+    RINOK(updateCallback->GetUpdateItemInfo(i,
+        &newData, &newProperties, &indexInArchive));
+    CUpdateItem updateItem;
+    updateItem.NewProperties = IntToBool(newProperties);
+    updateItem.NewData = IntToBool(newData);
+    updateItem.IndexInArchive = indexInArchive;
+    updateItem.IndexInClient = i;
+    updateItem.IsAnti = false;
+    updateItem.Size = 0;
+
+    if (updateItem.IndexInArchive != -1)
+    {
+      const CFileItem &fileItem = database->Files[updateItem.IndexInArchive];
+      updateItem.Name = fileItem.Name;
+      updateItem.IsDirectory = fileItem.IsDirectory;
+      updateItem.Size = fileItem.UnPackSize;
+      updateItem.IsAnti = fileItem.IsAnti;
+      
+      updateItem.CreationTime = fileItem.CreationTime;
+      updateItem.IsCreationTimeDefined = fileItem.IsCreationTimeDefined;
+      updateItem.LastWriteTime = fileItem.LastWriteTime;
+      updateItem.IsLastWriteTimeDefined = fileItem.IsLastWriteTimeDefined;
+      updateItem.LastAccessTime = fileItem.LastAccessTime;
+      updateItem.IsLastAccessTimeDefined = fileItem.IsLastAccessTimeDefined;
+    }
+
+    if (updateItem.NewProperties)
+    {
+      bool nameIsDefined;
+      bool folderStatusIsDefined;
+      {
+        NCOM::CPropVariant propVariant;
+        RINOK(updateCallback->GetProperty(i, kpidAttributes, &propVariant));
+        if (propVariant.vt == VT_EMPTY)
+          updateItem.AttributesAreDefined = false;
+        else if (propVariant.vt != VT_UI4)
+          return E_INVALIDARG;
+        else
+        {
+          updateItem.Attributes = propVariant.ulVal;
+          updateItem.AttributesAreDefined = true;
+        }
+      }
+      
+      RINOK(GetTime(updateCallback, i, kpidCreationTime, updateItem.CreationTime, updateItem.IsCreationTimeDefined));
+      RINOK(GetTime(updateCallback, i, kpidLastWriteTime, updateItem.LastWriteTime , updateItem.IsLastWriteTimeDefined));
+      RINOK(GetTime(updateCallback, i, kpidLastAccessTime, updateItem.LastAccessTime, updateItem.IsLastAccessTimeDefined));
+
+      {
+        NCOM::CPropVariant propVariant;
+        RINOK(updateCallback->GetProperty(i, kpidPath, &propVariant));
+        if (propVariant.vt == VT_EMPTY)
+          nameIsDefined = false;
+        else if (propVariant.vt != VT_BSTR)
+          return E_INVALIDARG;
+        else
+        {
+          updateItem.Name = NItemName::MakeLegalName(propVariant.bstrVal);
+          nameIsDefined = true;
+        }
+      }
+      {
+        NCOM::CPropVariant propVariant;
+        RINOK(updateCallback->GetProperty(i, kpidIsFolder, &propVariant));
+        if (propVariant.vt == VT_EMPTY)
+          folderStatusIsDefined = false;
+        else if (propVariant.vt != VT_BOOL)
+          return E_INVALIDARG;
+        else
+        {
+          updateItem.IsDirectory = (propVariant.boolVal != VARIANT_FALSE);
+          folderStatusIsDefined = true;
+        }
+      }
+
+      {
+        NCOM::CPropVariant propVariant;
+        RINOK(updateCallback->GetProperty(i, kpidIsAnti, &propVariant));
+        if (propVariant.vt == VT_EMPTY)
+          updateItem.IsAnti = false;
+        else if (propVariant.vt != VT_BOOL)
+          return E_INVALIDARG;
+        else
+          updateItem.IsAnti = (propVariant.boolVal != VARIANT_FALSE);
+      }
+
+      if (updateItem.IsAnti)
+      {
+        updateItem.AttributesAreDefined = false;
+
+        updateItem.IsCreationTimeDefined = false;
+        updateItem.IsLastWriteTimeDefined = false;
+        updateItem.IsLastAccessTimeDefined = false;
+        
+        updateItem.Size = 0;
+      }
+
+      if (!folderStatusIsDefined && updateItem.AttributesAreDefined)
+        updateItem.SetDirectoryStatusFromAttributes();
+    }
+
+    if (updateItem.NewData)
+    {
+      NCOM::CPropVariant propVariant;
+      RINOK(updateCallback->GetProperty(i, kpidSize, &propVariant));
+      if (propVariant.vt != VT_UI8)
+        return E_INVALIDARG;
+      updateItem.Size = (UInt64)propVariant.uhVal.QuadPart;
+      if (updateItem.Size != 0 && updateItem.IsAnti)
+        return E_INVALIDARG;
+    }
+    updateItems.Add(updateItem);
+  }
+
+  CCompressionMethodMode methodMode, headerMethod;
+  RINOK(SetCompressionMethod(methodMode, headerMethod));
+  #ifdef COMPRESS_MT
+  methodMode.NumThreads = _numThreads;
+  headerMethod.NumThreads = 1;
+  #endif
+
+  RINOK(SetPassword(methodMode, updateCallback));
+
+  bool compressMainHeader = _compressHeaders;  // check it
+
+  if (methodMode.PasswordIsDefined)
+  {
+    compressMainHeader = true; 
+    if(_encryptHeaders)
+      RINOK(SetPassword(headerMethod, updateCallback));
+  }
+
+  if (numItems < 2)
+    compressMainHeader = false;
+
+  CUpdateOptions options;
+  options.Method = &methodMode;
+  options.HeaderMethod = (_compressHeaders || 
+      (methodMode.PasswordIsDefined && _encryptHeaders)) ? 
+      &headerMethod : 0;
+  options.UseFilters = _level != 0 && _autoFilter;
+  options.MaxFilter = _level >= 8;
+
+  options.HeaderOptions.CompressMainHeader = compressMainHeader;
+  options.HeaderOptions.WriteModified = WriteModified;
+  options.HeaderOptions.WriteCreated = WriteCreated;
+  options.HeaderOptions.WriteAccessed = WriteAccessed;
+  
+  options.NumSolidFiles = _numSolidFiles;
+  options.NumSolidBytes = _numSolidBytes;
+  options.SolidExtension = _solidExtension;
+  options.RemoveSfxBlock = _removeSfxBlock;
+  options.VolumeMode = _volumeMode;
+  return Update(
+      EXTERNAL_CODECS_VARS
+      #ifdef _7Z_VOL
+      volume ? volume->Stream: 0, 
+      volume ? database: 0, 
+      #else
+      _inStream, 
+      database,
+      #endif
+      updateItems, outStream, updateCallback, options);
+  COM_TRY_END
+}
+
+static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream)
+{
+  stream = 0;
+  int index = ParseStringToUInt32(srcString, coder);
+  if (index == 0)
+    return E_INVALIDARG;
+  srcString.Delete(0, index);
+  if (srcString[0] == 'S')
+  {
+    srcString.Delete(0);
+    int index = ParseStringToUInt32(srcString, stream);
+    if (index == 0)
+      return E_INVALIDARG;
+    srcString.Delete(0, index);
+  }
+  return S_OK;
+}
+
+static HRESULT GetBindInfo(UString &srcString, CBind &bind)
+{
+  RINOK(GetBindInfoPart(srcString, bind.OutCoder, bind.OutStream));
+  if (srcString[0] != ':')
+    return E_INVALIDARG;
+  srcString.Delete(0);
+  RINOK(GetBindInfoPart(srcString, bind.InCoder, bind.InStream));
+  if (!srcString.IsEmpty())
+    return E_INVALIDARG;
+  return S_OK;
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
+{
+  COM_TRY_BEGIN
+  _binds.Clear();
+  BeforeSetProperty();
+
+  for (int i = 0; i < numProperties; i++)
+  {
+    UString name = names[i];
+    name.MakeUpper();
+    if (name.IsEmpty())
+      return E_INVALIDARG;
+
+    const PROPVARIANT &value = values[i];
+
+    if (name[0] == 'B')
+    {
+      name.Delete(0);
+      CBind bind;
+      RINOK(GetBindInfo(name, bind));
+      _binds.Add(bind);
+      continue;
+    }
+
+    RINOK(SetProperty(name, value));
+  }
+
+  return S_OK;
+  COM_TRY_END
+}  
+
+}}

+ 27 - 0
lzma/CPP/7zip/Archive/7z/7zHeader.cpp

@@ -0,0 +1,27 @@
+// 7z/Header.cpp
+
+#include "StdAfx.h"
+#include "7zHeader.h"
+
+namespace NArchive {
+namespace N7z {
+
+Byte kSignature[kSignatureSize] = {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C};
+#ifdef _7Z_VOL
+Byte kFinishSignature[kSignatureSize] = {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C + 1};
+#endif
+
+class SignatureInitializer
+{
+public:
+  SignatureInitializer() 
+  { 
+    kSignature[0]--; 
+    #ifdef _7Z_VOL
+    kFinishSignature[0]--;
+    #endif
+  };
+} g_SignatureInitializer;
+
+}}
+

+ 96 - 0
lzma/CPP/7zip/Archive/7z/7zHeader.h

@@ -0,0 +1,96 @@
+// 7z/7zHeader.h
+
+#ifndef __7Z_HEADER_H
+#define __7Z_HEADER_H
+
+#include "../../../Common/Types.h"
+
+namespace NArchive {
+namespace N7z {
+
+const int kSignatureSize = 6;
+extern Byte kSignature[kSignatureSize];
+
+// #define _7Z_VOL
+// 7z-MultiVolume is not finished yet.
+// It can work already, but I still do not like some 
+// things of that new multivolume format.
+// So please keep it commented.
+
+#ifdef _7Z_VOL
+extern Byte kFinishSignature[kSignatureSize];
+#endif
+
+struct CArchiveVersion
+{
+  Byte Major;
+  Byte Minor;
+};
+
+const Byte kMajorVersion = 0;
+
+struct CStartHeader
+{
+  UInt64 NextHeaderOffset;
+  UInt64 NextHeaderSize;
+  UInt32 NextHeaderCRC;
+};
+
+const UInt32 kStartHeaderSize = 20;
+
+#ifdef _7Z_VOL
+struct CFinishHeader: public CStartHeader
+{
+  UInt64 ArchiveStartOffset;  // data offset from end if that struct
+  UInt64 AdditionalStartBlockSize; // start  signature & start header size
+};
+
+const UInt32 kFinishHeaderSize = kStartHeaderSize + 16;
+#endif
+
+namespace NID
+{
+  enum EEnum
+  {
+    kEnd,
+
+    kHeader,
+
+    kArchiveProperties,
+    
+    kAdditionalStreamsInfo,
+    kMainStreamsInfo,
+    kFilesInfo,
+    
+    kPackInfo,
+    kUnPackInfo,
+    kSubStreamsInfo,
+
+    kSize,
+    kCRC,
+
+    kFolder,
+
+    kCodersUnPackSize,
+    kNumUnPackStream,
+
+    kEmptyStream,
+    kEmptyFile,
+    kAnti,
+
+    kName,
+    kCreationTime,
+    kLastAccessTime,
+    kLastWriteTime,
+    kWinAttributes,
+    kComment,
+
+    kEncodedHeader,
+
+    kStartPos
+  };
+}
+
+}}
+
+#endif

+ 1206 - 0
lzma/CPP/7zip/Archive/7z/7zIn.cpp

@@ -0,0 +1,1206 @@
+// 7zIn.cpp
+
+#include "StdAfx.h"
+
+#include "7zIn.h"
+#include "7zDecode.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+extern "C" 
+{ 
+#include "../../../../C/7zCrc.h"
+}
+
+// define FORMAT_7Z_RECOVERY if you want to recover multivolume archives with empty StartHeader 
+#ifndef _SFX
+#define FORMAT_7Z_RECOVERY
+#endif
+
+namespace NArchive {
+namespace N7z {
+
+class CInArchiveException {};
+
+static void ThrowException() { throw CInArchiveException(); }
+static inline void ThrowEndOfData()   { ThrowException(); }
+static inline void ThrowUnsupported() { ThrowException(); }
+static inline void ThrowIncorrect()   { ThrowException(); }
+static inline void ThrowUnsupportedVersion() { ThrowException(); }
+
+/*
+class CInArchiveException
+{
+public:
+  enum CCauseType
+  {
+    kUnsupportedVersion = 0,
+    kUnsupported,
+    kIncorrect, 
+    kEndOfData,
+  } Cause;
+  CInArchiveException(CCauseType cause): Cause(cause) {};
+};
+
+static void ThrowException(CInArchiveException::CCauseType c) { throw CInArchiveException(c); }
+static void ThrowEndOfData()   { ThrowException(CInArchiveException::kEndOfData); }
+static void ThrowUnsupported() { ThrowException(CInArchiveException::kUnsupported); }
+static void ThrowIncorrect()   { ThrowException(CInArchiveException::kIncorrect); }
+static void ThrowUnsupportedVersion() { ThrowException(CInArchiveException::kUnsupportedVersion); }
+*/
+
+class CStreamSwitch
+{
+  CInArchive *_archive;
+  bool _needRemove;
+public:
+  CStreamSwitch(): _needRemove(false) {}
+  ~CStreamSwitch() { Remove(); }
+  void Remove();
+  void Set(CInArchive *archive, const Byte *data, size_t size);
+  void Set(CInArchive *archive, const CByteBuffer &byteBuffer);
+  void Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector);
+};
+
+void CStreamSwitch::Remove()
+{
+  if (_needRemove)
+  {
+    _archive->DeleteByteStream();
+    _needRemove = false;
+  }
+}
+
+void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size)
+{
+  Remove();
+  _archive = archive;
+  _archive->AddByteStream(data, size);
+  _needRemove = true;
+}
+
+void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer)
+{
+  Set(archive, byteBuffer, byteBuffer.GetCapacity());
+}
+
+void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector)
+{
+  Remove();
+  Byte external = archive->ReadByte();
+  if (external != 0)
+  {
+    int dataIndex = (int)archive->ReadNum();
+    if (dataIndex < 0 || dataIndex >= dataVector->Size())
+      ThrowIncorrect();
+    Set(archive, (*dataVector)[dataIndex]);
+  }
+}
+
+#if defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || defined(__x86_64__)
+#define SZ_LITTLE_ENDIAN_UNALIGN
+#endif
+
+#ifdef SZ_LITTLE_ENDIAN_UNALIGN
+static inline UInt16 GetUInt16FromMem(const Byte *p) { return *(const UInt16 *)p; }
+static inline UInt32 GetUInt32FromMem(const Byte *p) { return *(const UInt32 *)p; }
+static inline UInt64 GetUInt64FromMem(const Byte *p) { return *(const UInt64 *)p; }
+#else
+static inline UInt16 GetUInt16FromMem(const Byte *p) { return p[0] | ((UInt16)p[1] << 8); }
+static inline UInt32 GetUInt32FromMem(const Byte *p) { return p[0] | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16) | ((UInt32)p[3] << 24); }
+static inline UInt64 GetUInt64FromMem(const Byte *p) { return GetUInt32FromMem(p) | ((UInt64)GetUInt32FromMem(p + 4) << 32); }
+#endif
+
+Byte CInByte2::ReadByte()
+{
+  if (_pos >= _size)
+    ThrowEndOfData();
+  return _buffer[_pos++];
+}
+
+void CInByte2::ReadBytes(Byte *data, size_t size)
+{
+  if (size > _size - _pos)
+    ThrowEndOfData();
+  for (size_t i = 0; i < size; i++)
+    data[i] = _buffer[_pos++];
+}
+
+void CInByte2::SkeepData(UInt64 size)
+{
+  if (size > _size - _pos)
+    ThrowEndOfData();
+}
+
+void CInByte2::SkeepData()
+{
+  SkeepData(ReadNumber());
+}
+
+UInt64 CInByte2::ReadNumber()
+{
+  if (_pos >= _size)
+    ThrowEndOfData();
+  Byte firstByte = _buffer[_pos++];
+  Byte mask = 0x80;
+  UInt64 value = 0;
+  for (int i = 0; i < 8; i++)
+  {
+    if ((firstByte & mask) == 0)
+    {
+      UInt64 highPart = firstByte & (mask - 1);
+      value += (highPart << (i * 8));
+      return value;
+    }
+    if (_pos >= _size)
+      ThrowEndOfData();
+    value |= ((UInt64)_buffer[_pos++] << (8 * i));
+    mask >>= 1;
+  }
+  return value;
+}
+
+CNum CInByte2::ReadNum()
+{ 
+  UInt64 value = ReadNumber(); 
+  if (value > kNumMax)
+    ThrowUnsupported();
+  return (CNum)value;
+}
+
+UInt32 CInByte2::ReadUInt32()
+{
+  if (_pos + 4 > _size)
+    ThrowEndOfData();
+  UInt32 res = GetUInt32FromMem(_buffer + _pos);
+  _pos += 4;
+  return res;
+}
+
+UInt64 CInByte2::ReadUInt64()
+{
+  if (_pos + 8 > _size)
+    ThrowEndOfData();
+  UInt64 res = GetUInt64FromMem(_buffer + _pos);
+  _pos += 8;
+  return res;
+}
+
+void CInByte2::ReadString(UString &s)
+{
+  const Byte *buf = _buffer + _pos;
+  size_t rem = (_size - _pos) / 2 * 2;
+  {
+    size_t i;
+    for (i = 0; i < rem; i += 2)
+      if (buf[i] == 0 && buf[i + 1] == 0)
+        break;
+    if (i == rem)
+      ThrowEndOfData();
+    rem = i;
+  }
+  int len = (int)(rem / 2);
+  if (len < 0 || (size_t)len * 2 != rem)
+    ThrowUnsupported();
+  wchar_t *p = s.GetBuffer(len);
+  int i;
+  for (i = 0; i < len; i++, buf += 2) 
+    p[i] = (wchar_t)GetUInt16FromMem(buf);
+  p[i] = 0;
+  s.ReleaseBuffer(len);
+  _pos += rem + 2;
+}
+
+static inline bool TestSignatureCandidate(const Byte *p)
+{
+  for (int i = 0; i < kSignatureSize; i++)
+    if (p[i] != kSignature[i])
+      return false;
+  return (p[0x1A] == 0 && p[0x1B] == 0);
+}
+
+HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+  UInt32 processedSize; 
+  RINOK(ReadStream(stream, _header, kHeaderSize, &processedSize));
+  if (processedSize != kHeaderSize)
+    return S_FALSE;
+  if (TestSignatureCandidate(_header))
+    return S_OK;
+
+  CByteBuffer byteBuffer;
+  const UInt32 kBufferSize = (1 << 16);
+  byteBuffer.SetCapacity(kBufferSize);
+  Byte *buffer = byteBuffer;
+  UInt32 numPrevBytes = kHeaderSize - 1;
+  memcpy(buffer, _header + 1, numPrevBytes);
+  UInt64 curTestPos = _arhiveBeginStreamPosition + 1;
+  for (;;)
+  {
+    if (searchHeaderSizeLimit != NULL)
+      if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit)
+        break;
+    UInt32 numReadBytes = kBufferSize - numPrevBytes;
+    RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize));
+    UInt32 numBytesInBuffer = numPrevBytes + processedSize;
+    if (numBytesInBuffer < kHeaderSize)
+      break;
+    UInt32 numTests = numBytesInBuffer - kHeaderSize + 1;
+    for(UInt32 pos = 0; pos < numTests; pos++, curTestPos++)
+    { 
+      if (TestSignatureCandidate(buffer + pos))
+      {
+        memcpy(_header, buffer + pos, kHeaderSize);
+        _arhiveBeginStreamPosition = curTestPos;
+        return stream->Seek(curTestPos + kHeaderSize, STREAM_SEEK_SET, NULL);
+      }
+    }
+    numPrevBytes = numBytesInBuffer - numTests;
+    memmove(buffer, buffer + numTests, numPrevBytes);
+  }
+  return S_FALSE;
+}
+
+// S_FALSE means that file is not archive
+HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+  Close();
+  RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition))
+  RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
+  _stream = stream;
+  return S_OK;
+}
+  
+void CInArchive::Close()
+{
+  _stream.Release();
+}
+
+void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */)
+{
+  for (;;)
+  {
+    if (ReadID() == NID::kEnd)
+      break;
+    SkeepData();
+  }
+}
+
+void CInArchive::GetNextFolderItem(CFolder &folder)
+{
+  CNum numCoders = ReadNum();
+
+  folder.Coders.Clear();
+  folder.Coders.Reserve((int)numCoders);
+  CNum numInStreams = 0;
+  CNum numOutStreams = 0;
+  CNum i;
+  for (i = 0; i < numCoders; i++)
+  {
+    folder.Coders.Add(CCoderInfo());
+    CCoderInfo &coder = folder.Coders.Back();
+
+    {
+      Byte mainByte = ReadByte();
+      int idSize = (mainByte & 0xF);
+      Byte longID[15];
+      ReadBytes(longID, idSize);
+      if (idSize > 8)
+        ThrowUnsupported();
+      UInt64 id = 0;
+      for (int j = 0; j < idSize; j++)
+        id |= (UInt64)longID[idSize - 1 - j] << (8 * j);
+      coder.MethodID = id;
+
+      if ((mainByte & 0x10) != 0)
+      {
+        coder.NumInStreams = ReadNum();
+        coder.NumOutStreams = ReadNum();
+      }
+      else
+      {
+        coder.NumInStreams = 1;
+        coder.NumOutStreams = 1;
+      }
+      if ((mainByte & 0x20) != 0)
+      {
+        CNum propertiesSize = ReadNum();
+        coder.Properties.SetCapacity((size_t)propertiesSize);
+        ReadBytes((Byte *)coder.Properties, (size_t)propertiesSize);
+      }
+      if ((mainByte & 0x80) != 0)
+        ThrowUnsupported();
+    }
+    numInStreams += coder.NumInStreams;
+    numOutStreams += coder.NumOutStreams;
+  }
+
+  CNum numBindPairs;
+  numBindPairs = numOutStreams - 1;
+  folder.BindPairs.Clear();
+  folder.BindPairs.Reserve(numBindPairs);
+  for (i = 0; i < numBindPairs; i++)
+  {
+    CBindPair bindPair;
+    bindPair.InIndex = ReadNum();
+    bindPair.OutIndex = ReadNum(); 
+    folder.BindPairs.Add(bindPair);
+  }
+
+  CNum numPackedStreams = numInStreams - numBindPairs;
+  folder.PackStreams.Reserve(numPackedStreams);
+  if (numPackedStreams == 1)
+  {
+    for (CNum j = 0; j < numInStreams; j++)
+      if (folder.FindBindPairForInStream(j) < 0)
+      {
+        folder.PackStreams.Add(j);
+        break;
+      }
+  }
+  else
+    for(i = 0; i < numPackedStreams; i++)
+      folder.PackStreams.Add(ReadNum());
+}
+
+void CInArchive::WaitAttribute(UInt64 attribute)
+{
+  for (;;)
+  {
+    UInt64 type = ReadID();
+    if (type == attribute)
+      return;
+    if (type == NID::kEnd)
+      ThrowIncorrect();
+    SkeepData();
+  }
+}
+
+void CInArchive::ReadHashDigests(int numItems,
+    CRecordVector<bool> &digestsDefined, 
+    CRecordVector<UInt32> &digests)
+{
+  ReadBoolVector2(numItems, digestsDefined);
+  digests.Clear();
+  digests.Reserve(numItems);
+  for(int i = 0; i < numItems; i++)
+  {
+    UInt32 crc = 0;
+    if (digestsDefined[i])
+      crc = ReadUInt32();
+    digests.Add(crc);
+  }
+}
+
+void CInArchive::ReadPackInfo(
+    UInt64 &dataOffset,
+    CRecordVector<UInt64> &packSizes,
+    CRecordVector<bool> &packCRCsDefined,
+    CRecordVector<UInt32> &packCRCs)
+{
+  dataOffset = ReadNumber();
+  CNum numPackStreams = ReadNum();
+
+  WaitAttribute(NID::kSize);
+  packSizes.Clear();
+  packSizes.Reserve(numPackStreams);
+  for (CNum i = 0; i < numPackStreams; i++)
+    packSizes.Add(ReadNumber());
+
+  UInt64 type;
+  for (;;)
+  {
+    type = ReadID();
+    if (type == NID::kEnd)
+      break;
+    if (type == NID::kCRC)
+    {
+      ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs); 
+      continue;
+    }
+    SkeepData();
+  }
+  if (packCRCsDefined.IsEmpty())
+  {
+    packCRCsDefined.Reserve(numPackStreams);
+    packCRCsDefined.Clear();
+    packCRCs.Reserve(numPackStreams);
+    packCRCs.Clear();
+    for(CNum i = 0; i < numPackStreams; i++)
+    {
+      packCRCsDefined.Add(false);
+      packCRCs.Add(0);
+    }
+  }
+}
+
+void CInArchive::ReadUnPackInfo(
+    const CObjectVector<CByteBuffer> *dataVector,
+    CObjectVector<CFolder> &folders)
+{
+  WaitAttribute(NID::kFolder);
+  CNum numFolders = ReadNum();
+
+  {
+    CStreamSwitch streamSwitch;
+    streamSwitch.Set(this, dataVector);
+    folders.Clear();
+    folders.Reserve(numFolders);
+    for(CNum i = 0; i < numFolders; i++)
+    {
+      folders.Add(CFolder());
+      GetNextFolderItem(folders.Back());
+    }
+  }
+
+  WaitAttribute(NID::kCodersUnPackSize);
+
+  CNum i;
+  for (i = 0; i < numFolders; i++)
+  {
+    CFolder &folder = folders[i];
+    CNum numOutStreams = folder.GetNumOutStreams();
+    folder.UnPackSizes.Reserve(numOutStreams);
+    for (CNum j = 0; j < numOutStreams; j++)
+      folder.UnPackSizes.Add(ReadNumber());
+  }
+
+  for (;;)
+  {
+    UInt64 type = ReadID();
+    if (type == NID::kEnd)
+      return;
+    if (type == NID::kCRC)
+    {
+      CRecordVector<bool> crcsDefined;
+      CRecordVector<UInt32> crcs;
+      ReadHashDigests(numFolders, crcsDefined, crcs); 
+      for(i = 0; i < numFolders; i++)
+      {
+        CFolder &folder = folders[i];
+        folder.UnPackCRCDefined = crcsDefined[i];
+        folder.UnPackCRC = crcs[i];
+      }
+      continue;
+    }
+    SkeepData();
+  }
+}
+
+void CInArchive::ReadSubStreamsInfo(
+    const CObjectVector<CFolder> &folders,
+    CRecordVector<CNum> &numUnPackStreamsInFolders,
+    CRecordVector<UInt64> &unPackSizes,
+    CRecordVector<bool> &digestsDefined, 
+    CRecordVector<UInt32> &digests)
+{
+  numUnPackStreamsInFolders.Clear();
+  numUnPackStreamsInFolders.Reserve(folders.Size());
+  UInt64 type;
+  for (;;)
+  {
+    type = ReadID();
+    if (type == NID::kNumUnPackStream)
+    {
+      for(int i = 0; i < folders.Size(); i++)
+        numUnPackStreamsInFolders.Add(ReadNum());
+      continue;
+    }
+    if (type == NID::kCRC || type == NID::kSize)
+      break;
+    if (type == NID::kEnd)
+      break;
+    SkeepData();
+  }
+
+  if (numUnPackStreamsInFolders.IsEmpty())
+    for(int i = 0; i < folders.Size(); i++)
+      numUnPackStreamsInFolders.Add(1);
+
+  int i;
+  for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
+  {
+    // v3.13 incorrectly worked with empty folders
+    // v4.07: we check that folder is empty
+    CNum numSubstreams = numUnPackStreamsInFolders[i];
+    if (numSubstreams == 0)
+      continue;
+    UInt64 sum = 0;
+    for (CNum j = 1; j < numSubstreams; j++)
+      if (type == NID::kSize)
+      {
+        UInt64 size = ReadNumber();
+        unPackSizes.Add(size);
+        sum += size;
+      }
+    unPackSizes.Add(folders[i].GetUnPackSize() - sum);
+  }
+  if (type == NID::kSize)
+    type = ReadID();
+
+  int numDigests = 0;
+  int numDigestsTotal = 0;
+  for(i = 0; i < folders.Size(); i++)
+  {
+    CNum numSubstreams = numUnPackStreamsInFolders[i];
+    if (numSubstreams != 1 || !folders[i].UnPackCRCDefined)
+      numDigests += numSubstreams;
+    numDigestsTotal += numSubstreams;
+  }
+
+  for (;;)
+  {
+    if (type == NID::kCRC)
+    {
+      CRecordVector<bool> digestsDefined2; 
+      CRecordVector<UInt32> digests2;
+      ReadHashDigests(numDigests, digestsDefined2, digests2);
+      int digestIndex = 0;
+      for (i = 0; i < folders.Size(); i++)
+      {
+        CNum numSubstreams = numUnPackStreamsInFolders[i];
+        const CFolder &folder = folders[i];
+        if (numSubstreams == 1 && folder.UnPackCRCDefined)
+        {
+          digestsDefined.Add(true);
+          digests.Add(folder.UnPackCRC);
+        }
+        else
+          for (CNum j = 0; j < numSubstreams; j++, digestIndex++)
+          {
+            digestsDefined.Add(digestsDefined2[digestIndex]);
+            digests.Add(digests2[digestIndex]);
+          }
+      }
+    }
+    else if (type == NID::kEnd)
+    {
+      if (digestsDefined.IsEmpty())
+      {
+        digestsDefined.Clear();
+        digests.Clear();
+        for (int i = 0; i < numDigestsTotal; i++)
+        {
+          digestsDefined.Add(false);
+          digests.Add(0);
+        }
+      }
+      return;
+    }
+    else
+      SkeepData();
+    type = ReadID();
+  }
+}
+
+void CInArchive::ReadStreamsInfo(
+    const CObjectVector<CByteBuffer> *dataVector,
+    UInt64 &dataOffset,
+    CRecordVector<UInt64> &packSizes,
+    CRecordVector<bool> &packCRCsDefined,
+    CRecordVector<UInt32> &packCRCs,
+    CObjectVector<CFolder> &folders,
+    CRecordVector<CNum> &numUnPackStreamsInFolders,
+    CRecordVector<UInt64> &unPackSizes,
+    CRecordVector<bool> &digestsDefined, 
+    CRecordVector<UInt32> &digests)
+{
+  for (;;)
+  {
+    UInt64 type = ReadID();
+    if (type > ((UInt32)1 << 30))
+      ThrowIncorrect();
+    switch((UInt32)type)
+    {
+      case NID::kEnd:
+        return;
+      case NID::kPackInfo:
+      {
+        ReadPackInfo(dataOffset, packSizes, packCRCsDefined, packCRCs);
+        break;
+      }
+      case NID::kUnPackInfo:
+      {
+        ReadUnPackInfo(dataVector, folders);
+        break;
+      }
+      case NID::kSubStreamsInfo:
+      {
+        ReadSubStreamsInfo(folders, numUnPackStreamsInFolders,
+            unPackSizes, digestsDefined, digests);
+        break;
+      }
+      default:
+        ThrowIncorrect();
+    }
+  }
+}
+
+void CInArchive::ReadBoolVector(int numItems, CBoolVector &v)
+{
+  v.Clear();
+  v.Reserve(numItems);
+  Byte b = 0;
+  Byte mask = 0;
+  for(int i = 0; i < numItems; i++)
+  {
+    if (mask == 0)
+    {
+      b = ReadByte();
+      mask = 0x80;
+    }
+    v.Add((b & mask) != 0);
+    mask >>= 1;
+  }
+}
+
+void CInArchive::ReadBoolVector2(int numItems, CBoolVector &v)
+{
+  Byte allAreDefined = ReadByte();
+  if (allAreDefined == 0)
+  {
+    ReadBoolVector(numItems, v);
+    return;
+  }
+  v.Clear();
+  v.Reserve(numItems);
+  for (int i = 0; i < numItems; i++)
+    v.Add(true);
+}
+
+void CInArchive::ReadTime(const CObjectVector<CByteBuffer> &dataVector,
+    CObjectVector<CFileItem> &files, UInt32 type)
+{
+  CBoolVector boolVector;
+  ReadBoolVector2(files.Size(), boolVector);
+
+  CStreamSwitch streamSwitch;
+  streamSwitch.Set(this, &dataVector);
+
+  for(int i = 0; i < files.Size(); i++)
+  {
+    CFileItem &file = files[i];
+    CArchiveFileTime fileTime;
+    fileTime.dwLowDateTime = 0;
+    fileTime.dwHighDateTime = 0;
+    bool defined = boolVector[i];
+    if (defined)
+    {
+      fileTime.dwLowDateTime = ReadUInt32();
+      fileTime.dwHighDateTime = ReadUInt32();
+    }
+    switch(type)
+    {
+      case NID::kCreationTime:
+        file.IsCreationTimeDefined = defined;
+        if (defined)
+          file.CreationTime = fileTime;
+        break;
+      case NID::kLastWriteTime:
+        file.IsLastWriteTimeDefined = defined;
+        if (defined)
+          file.LastWriteTime = fileTime;
+        break;
+      case NID::kLastAccessTime:
+        file.IsLastAccessTimeDefined = defined;
+        if (defined)
+          file.LastAccessTime = fileTime;
+        break;
+    }
+  }
+}
+
+HRESULT CInArchive::ReadAndDecodePackedStreams(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    UInt64 baseOffset, 
+    UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector
+    #ifndef _NO_CRYPTO
+    , ICryptoGetTextPassword *getTextPassword
+    #endif
+    )
+{
+  CRecordVector<UInt64> packSizes;
+  CRecordVector<bool> packCRCsDefined;
+  CRecordVector<UInt32> packCRCs;
+  CObjectVector<CFolder> folders;
+  
+  CRecordVector<CNum> numUnPackStreamsInFolders;
+  CRecordVector<UInt64> unPackSizes;
+  CRecordVector<bool> digestsDefined;
+  CRecordVector<UInt32> digests;
+  
+  ReadStreamsInfo(NULL, 
+    dataOffset,
+    packSizes, 
+    packCRCsDefined, 
+    packCRCs, 
+    folders,
+    numUnPackStreamsInFolders,
+    unPackSizes,
+    digestsDefined, 
+    digests);
+  
+  // database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader;
+  
+  CNum packIndex = 0;
+  CDecoder decoder(
+    #ifdef _ST_MODE
+    false
+    #else
+    true
+    #endif
+    );
+  UInt64 dataStartPos = baseOffset + dataOffset;
+  for(int i = 0; i < folders.Size(); i++)
+  {
+    const CFolder &folder = folders[i];
+    dataVector.Add(CByteBuffer());
+    CByteBuffer &data = dataVector.Back();
+    UInt64 unPackSize64 = folder.GetUnPackSize();
+    size_t unPackSize = (size_t)unPackSize64;
+    if (unPackSize != unPackSize64)
+      ThrowUnsupported();
+    data.SetCapacity(unPackSize);
+    
+    CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2;
+    CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+    outStreamSpec->Init(data, unPackSize);
+    
+    HRESULT result = decoder.Decode(
+      EXTERNAL_CODECS_LOC_VARS
+      _stream, dataStartPos, 
+      &packSizes[packIndex], folder, outStream, NULL
+      #ifndef _NO_CRYPTO
+      , getTextPassword
+      #endif
+      #ifdef COMPRESS_MT
+      , false, 1
+      #endif
+      );
+    RINOK(result);
+    
+    if (folder.UnPackCRCDefined)
+      if (CrcCalc(data, unPackSize) != folder.UnPackCRC)
+        ThrowIncorrect();
+      for (int j = 0; j < folder.PackStreams.Size(); j++)
+        dataStartPos += packSizes[packIndex++];
+  }
+  return S_OK;
+}
+
+HRESULT CInArchive::ReadHeader(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    CArchiveDatabaseEx &database
+    #ifndef _NO_CRYPTO
+    , ICryptoGetTextPassword *getTextPassword
+    #endif
+    )
+{
+  UInt64 type = ReadID();
+
+  if (type == NID::kArchiveProperties)
+  {
+    ReadArchiveProperties(database.ArchiveInfo);
+    type = ReadID();
+  }
+ 
+  CObjectVector<CByteBuffer> dataVector;
+  
+  if (type == NID::kAdditionalStreamsInfo)
+  {
+    HRESULT result = ReadAndDecodePackedStreams(
+        EXTERNAL_CODECS_LOC_VARS
+        database.ArchiveInfo.StartPositionAfterHeader, 
+        database.ArchiveInfo.DataStartPosition2,
+        dataVector
+        #ifndef _NO_CRYPTO
+        , getTextPassword
+        #endif
+        );
+    RINOK(result);
+    database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader;
+    type = ReadID();
+  }
+
+  CRecordVector<UInt64> unPackSizes;
+  CRecordVector<bool> digestsDefined;
+  CRecordVector<UInt32> digests;
+  
+  if (type == NID::kMainStreamsInfo)
+  {
+    ReadStreamsInfo(&dataVector,
+        database.ArchiveInfo.DataStartPosition,
+        database.PackSizes, 
+        database.PackCRCsDefined, 
+        database.PackCRCs, 
+        database.Folders,
+        database.NumUnPackStreamsVector,
+        unPackSizes,
+        digestsDefined,
+        digests);
+    database.ArchiveInfo.DataStartPosition += database.ArchiveInfo.StartPositionAfterHeader;
+    type = ReadID();
+  }
+  else
+  {
+    for(int i = 0; i < database.Folders.Size(); i++)
+    {
+      database.NumUnPackStreamsVector.Add(1);
+      CFolder &folder = database.Folders[i];
+      unPackSizes.Add(folder.GetUnPackSize());
+      digestsDefined.Add(folder.UnPackCRCDefined);
+      digests.Add(folder.UnPackCRC);
+    }
+  }
+
+  database.Files.Clear();
+
+  if (type == NID::kEnd)
+    return S_OK;
+  if (type != NID::kFilesInfo)
+    ThrowIncorrect();
+  
+  CNum numFiles = ReadNum();
+  database.Files.Reserve(numFiles);
+  CNum i;
+  for(i = 0; i < numFiles; i++)
+    database.Files.Add(CFileItem());
+
+  database.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize);
+  if (!database.PackSizes.IsEmpty())
+    database.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo);
+  if (numFiles > 0  && !digests.IsEmpty())
+    database.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC);
+
+  CBoolVector emptyStreamVector;
+  emptyStreamVector.Reserve((int)numFiles);
+  for(i = 0; i < numFiles; i++)
+    emptyStreamVector.Add(false);
+  CBoolVector emptyFileVector;
+  CBoolVector antiFileVector;
+  CNum numEmptyStreams = 0;
+
+  for (;;)
+  {
+    UInt64 type = ReadID();
+    if (type == NID::kEnd)
+      break;
+    UInt64 size = ReadNumber();
+    bool isKnownType = true;
+    if (type > ((UInt32)1 << 30))
+      isKnownType = false;
+    else switch((UInt32)type)
+    {
+      case NID::kName:
+      {
+        CStreamSwitch streamSwitch;
+        streamSwitch.Set(this, &dataVector);
+        for(int i = 0; i < database.Files.Size(); i++)
+          _inByteBack->ReadString(database.Files[i].Name);
+        break;
+      }
+      case NID::kWinAttributes:
+      {
+        CBoolVector boolVector;
+        ReadBoolVector2(database.Files.Size(), boolVector);
+        CStreamSwitch streamSwitch;
+        streamSwitch.Set(this, &dataVector);
+        for(i = 0; i < numFiles; i++)
+        {
+          CFileItem &file = database.Files[i];
+          file.AreAttributesDefined = boolVector[i];
+          if (file.AreAttributesDefined)
+            file.Attributes = ReadUInt32();
+        }
+        break;
+      }
+      case NID::kStartPos:
+      {
+        CBoolVector boolVector;
+        ReadBoolVector2(database.Files.Size(), boolVector);
+        CStreamSwitch streamSwitch;
+        streamSwitch.Set(this, &dataVector);
+        for(i = 0; i < numFiles; i++)
+        {
+          CFileItem &file = database.Files[i];
+          file.IsStartPosDefined = boolVector[i];
+          if (file.IsStartPosDefined)
+            file.StartPos = ReadUInt64();
+        }
+        break;
+      }
+      case NID::kEmptyStream:
+      {
+        ReadBoolVector(numFiles, emptyStreamVector);
+        for (i = 0; i < (CNum)emptyStreamVector.Size(); i++)
+          if (emptyStreamVector[i])
+            numEmptyStreams++;
+        emptyFileVector.Reserve(numEmptyStreams);
+        antiFileVector.Reserve(numEmptyStreams);
+        for (i = 0; i < numEmptyStreams; i++)
+        {
+          emptyFileVector.Add(false);
+          antiFileVector.Add(false);
+        }
+        break;
+      }
+      case NID::kEmptyFile:
+      {
+        ReadBoolVector(numEmptyStreams, emptyFileVector);
+        break;
+      }
+      case NID::kAnti:
+      {
+        ReadBoolVector(numEmptyStreams, antiFileVector);
+        break;
+      }
+      case NID::kCreationTime:
+      case NID::kLastWriteTime:
+      case NID::kLastAccessTime:
+      {
+        ReadTime(dataVector, database.Files, (UInt32)type);
+        break;
+      }
+      default:
+        isKnownType = false;
+    }
+    if (isKnownType)
+      database.ArchiveInfo.FileInfoPopIDs.Add(type);
+    else
+      SkeepData(size);
+  }
+
+  CNum emptyFileIndex = 0;
+  CNum sizeIndex = 0;
+  for(i = 0; i < numFiles; i++)
+  {
+    CFileItem &file = database.Files[i];
+    file.HasStream = !emptyStreamVector[i];
+    if(file.HasStream)
+    {
+      file.IsDirectory = false;
+      file.IsAnti = false;
+      file.UnPackSize = unPackSizes[sizeIndex];
+      file.FileCRC = digests[sizeIndex];
+      file.IsFileCRCDefined = digestsDefined[sizeIndex];
+      sizeIndex++;
+    }
+    else
+    {
+      file.IsDirectory = !emptyFileVector[emptyFileIndex];
+      file.IsAnti = antiFileVector[emptyFileIndex];
+      emptyFileIndex++;
+      file.UnPackSize = 0;
+      file.IsFileCRCDefined = false;
+    }
+  }
+  return S_OK;
+}
+
+
+void CArchiveDatabaseEx::FillFolderStartPackStream()
+{
+  FolderStartPackStreamIndex.Clear();
+  FolderStartPackStreamIndex.Reserve(Folders.Size());
+  CNum startPos = 0;
+  for(int i = 0; i < Folders.Size(); i++)
+  {
+    FolderStartPackStreamIndex.Add(startPos);
+    startPos += (CNum)Folders[i].PackStreams.Size();
+  }
+}
+
+void CArchiveDatabaseEx::FillStartPos()
+{
+  PackStreamStartPositions.Clear();
+  PackStreamStartPositions.Reserve(PackSizes.Size());
+  UInt64 startPos = 0;
+  for(int i = 0; i < PackSizes.Size(); i++)
+  {
+    PackStreamStartPositions.Add(startPos);
+    startPos += PackSizes[i];
+  }
+}
+
+void CArchiveDatabaseEx::FillFolderStartFileIndex()
+{
+  FolderStartFileIndex.Clear();
+  FolderStartFileIndex.Reserve(Folders.Size());
+  FileIndexToFolderIndexMap.Clear();
+  FileIndexToFolderIndexMap.Reserve(Files.Size());
+  
+  int folderIndex = 0;
+  CNum indexInFolder = 0;
+  for (int i = 0; i < Files.Size(); i++)
+  {
+    const CFileItem &file = Files[i];
+    bool emptyStream = !file.HasStream;
+    if (emptyStream && indexInFolder == 0)
+    {
+      FileIndexToFolderIndexMap.Add(kNumNoIndex);
+      continue;
+    }
+    if (indexInFolder == 0)
+    {
+      // v3.13 incorrectly worked with empty folders
+      // v4.07: Loop for skipping empty folders
+      for (;;)
+      {
+        if (folderIndex >= Folders.Size())
+          ThrowIncorrect();
+        FolderStartFileIndex.Add(i); // check it
+        if (NumUnPackStreamsVector[folderIndex] != 0)
+          break;
+        folderIndex++;
+      }
+    }
+    FileIndexToFolderIndexMap.Add(folderIndex);
+    if (emptyStream)
+      continue;
+    indexInFolder++;
+    if (indexInFolder >= NumUnPackStreamsVector[folderIndex])
+    {
+      folderIndex++;
+      indexInFolder = 0;
+    }
+  }
+}
+
+HRESULT CInArchive::ReadDatabase2(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    CArchiveDatabaseEx &database
+    #ifndef _NO_CRYPTO
+    , ICryptoGetTextPassword *getTextPassword
+    #endif
+    )
+{
+  database.Clear();
+  database.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;
+
+  database.ArchiveInfo.Version.Major = _header[6];
+  database.ArchiveInfo.Version.Minor = _header[7];
+
+  if (database.ArchiveInfo.Version.Major != kMajorVersion)
+    ThrowUnsupportedVersion();
+
+  UInt32 crcFromArchive = GetUInt32FromMem(_header + 8);
+  UInt64 nextHeaderOffset = GetUInt64FromMem(_header + 0xC);
+  UInt64 nextHeaderSize = GetUInt64FromMem(_header + 0x14);
+  UInt32 nextHeaderCRC =  GetUInt32FromMem(_header + 0x1C);
+  UInt32 crc = CrcCalc(_header + 0xC, 20);
+
+  #ifdef FORMAT_7Z_RECOVERY
+  if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)
+  {
+    UInt64 cur, cur2;
+    RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur));
+    const int kCheckSize = 500;
+    Byte buf[kCheckSize];
+    RINOK(_stream->Seek(0, STREAM_SEEK_END, &cur2));
+    int checkSize = kCheckSize;
+    if (cur2 - cur < kCheckSize)
+      checkSize = (int)(cur2 - cur);
+    RINOK(_stream->Seek(-checkSize, STREAM_SEEK_END, &cur2));
+    
+    UInt32 realProcessedSize;
+    RINOK(_stream->Read(buf, (UInt32)kCheckSize, &realProcessedSize));
+
+    int i;
+    for (i = (int)realProcessedSize - 2; i >= 0; i--)
+      if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04)
+        break;
+    if (i < 0)
+      return S_FALSE;
+    nextHeaderSize = realProcessedSize - i;
+    nextHeaderOffset = cur2 - cur + i;
+    nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);
+    RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL));
+  }
+  #endif
+
+  #ifdef FORMAT_7Z_RECOVERY
+  crcFromArchive = crc;
+  #endif
+
+  database.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;
+
+  if (crc != crcFromArchive)
+    ThrowIncorrect();
+
+  if (nextHeaderSize == 0)
+    return S_OK;
+
+  if (nextHeaderSize > (UInt64)0xFFFFFFFF)
+    return S_FALSE;
+
+  RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL));
+
+  CByteBuffer buffer2;
+  buffer2.SetCapacity((size_t)nextHeaderSize);
+
+  UInt32 realProcessedSize;
+  RINOK(_stream->Read(buffer2, (UInt32)nextHeaderSize, &realProcessedSize));
+  if (realProcessedSize != (UInt32)nextHeaderSize)
+    return S_FALSE;
+  if (CrcCalc(buffer2, (UInt32)nextHeaderSize) != nextHeaderCRC)
+    ThrowIncorrect();
+  
+  CStreamSwitch streamSwitch;
+  streamSwitch.Set(this, buffer2);
+  
+  CObjectVector<CByteBuffer> dataVector;
+  
+  for (;;)
+  {
+    UInt64 type = ReadID();
+    if (type == NID::kHeader)
+      break;
+    if (type != NID::kEncodedHeader)
+      ThrowIncorrect();
+    HRESULT result = ReadAndDecodePackedStreams(
+        EXTERNAL_CODECS_LOC_VARS
+        database.ArchiveInfo.StartPositionAfterHeader, 
+        database.ArchiveInfo.DataStartPosition2,
+        dataVector
+        #ifndef _NO_CRYPTO
+        , getTextPassword
+        #endif
+        );
+    RINOK(result);
+    if (dataVector.Size() == 0)
+      return S_OK;
+    if (dataVector.Size() > 1)
+      ThrowIncorrect();
+    streamSwitch.Remove();
+    streamSwitch.Set(this, dataVector.Front());
+  }
+
+  return ReadHeader(
+    EXTERNAL_CODECS_LOC_VARS
+    database
+    #ifndef _NO_CRYPTO
+    , getTextPassword
+    #endif
+    );
+}
+
+HRESULT CInArchive::ReadDatabase(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    CArchiveDatabaseEx &database
+    #ifndef _NO_CRYPTO
+    , ICryptoGetTextPassword *getTextPassword
+    #endif
+    )
+{
+  try
+  {
+    return ReadDatabase2(
+      EXTERNAL_CODECS_LOC_VARS database
+      #ifndef _NO_CRYPTO
+      , getTextPassword
+      #endif
+      );
+  }
+  catch(CInArchiveException &) { return S_FALSE; }
+}
+
+}}

+ 235 - 0
lzma/CPP/7zip/Archive/7z/7zIn.h

@@ -0,0 +1,235 @@
+// 7zIn.h
+
+#ifndef __7Z_IN_H
+#define __7Z_IN_H
+
+#include "../../../Common/MyCom.h"
+#include "../../IStream.h"
+#include "../../IPassword.h"
+#include "../../Common/CreateCoder.h"
+#include "../../Common/InBuffer.h"
+
+#include "7zItem.h"
+ 
+namespace NArchive {
+namespace N7z {
+  
+struct CInArchiveInfo
+{
+  CArchiveVersion Version;
+  UInt64 StartPosition;
+  UInt64 StartPositionAfterHeader;
+  UInt64 DataStartPosition;
+  UInt64 DataStartPosition2;
+  CRecordVector<UInt64> FileInfoPopIDs;
+  void Clear()
+  {
+    FileInfoPopIDs.Clear();
+  }
+};
+
+struct CArchiveDatabaseEx: public CArchiveDatabase
+{
+  CInArchiveInfo ArchiveInfo;
+  CRecordVector<UInt64> PackStreamStartPositions;
+  CRecordVector<CNum> FolderStartPackStreamIndex;
+  CRecordVector<CNum> FolderStartFileIndex;
+  CRecordVector<CNum> FileIndexToFolderIndexMap;
+
+  void Clear()
+  {
+    CArchiveDatabase::Clear();
+    ArchiveInfo.Clear();
+    PackStreamStartPositions.Clear();
+    FolderStartPackStreamIndex.Clear();
+    FolderStartFileIndex.Clear();
+    FileIndexToFolderIndexMap.Clear();
+  }
+
+  void FillFolderStartPackStream();
+  void FillStartPos();
+  void FillFolderStartFileIndex();
+
+  void Fill()
+  {
+    FillFolderStartPackStream();
+    FillStartPos();
+    FillFolderStartFileIndex();
+  }
+  
+  UInt64 GetFolderStreamPos(int folderIndex, int indexInFolder) const
+  {
+    return ArchiveInfo.DataStartPosition +
+        PackStreamStartPositions[FolderStartPackStreamIndex[folderIndex] + indexInFolder];
+  }
+  
+  UInt64 GetFolderFullPackSize(int folderIndex) const 
+  {
+    CNum packStreamIndex = FolderStartPackStreamIndex[folderIndex];
+    const CFolder &folder = Folders[folderIndex];
+    UInt64 size = 0;
+    for (int i = 0; i < folder.PackStreams.Size(); i++)
+      size += PackSizes[packStreamIndex + i];
+    return size;
+  }
+  
+  UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const 
+  {
+    return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex];
+  }
+
+  UInt64 GetFilePackSize(CNum fileIndex) const
+  {
+    CNum folderIndex = FileIndexToFolderIndexMap[fileIndex];
+    if (folderIndex != kNumNoIndex)
+      if (FolderStartFileIndex[folderIndex] == fileIndex)
+        return GetFolderFullPackSize(folderIndex);
+    return 0;
+  }
+};
+
+class CInByte2
+{
+  const Byte *_buffer;
+  size_t _size;
+  size_t _pos;
+public:
+  void Init(const Byte *buffer, size_t size)
+  {
+    _buffer = buffer;
+    _size = size;
+    _pos = 0;
+  }
+  Byte ReadByte();
+  void ReadBytes(Byte *data, size_t size);
+  void SkeepData(UInt64 size);
+  void SkeepData();
+  UInt64 ReadNumber();
+  CNum ReadNum();
+  UInt32 ReadUInt32();
+  UInt64 ReadUInt64();
+  void ReadString(UString &s);
+};
+
+class CStreamSwitch;
+
+const UInt32 kHeaderSize = 32;
+
+class CInArchive
+{
+  friend class CStreamSwitch;
+
+  CMyComPtr<IInStream> _stream;
+
+  CObjectVector<CInByte2> _inByteVector;
+  CInByte2 *_inByteBack;
+ 
+  UInt64 _arhiveBeginStreamPosition;
+
+  Byte _header[kHeaderSize];
+
+  void AddByteStream(const Byte *buffer, size_t size)
+  {
+    _inByteVector.Add(CInByte2());
+    _inByteBack = &_inByteVector.Back();
+    _inByteBack->Init(buffer, size);
+  }
+  
+  void DeleteByteStream()
+  {
+    _inByteVector.DeleteBack();
+    if (!_inByteVector.IsEmpty())
+      _inByteBack = &_inByteVector.Back();
+  }
+
+private:
+  HRESULT FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
+  
+  void ReadBytes(Byte *data, size_t size) { _inByteBack->ReadBytes(data, size); }
+  Byte ReadByte() { return _inByteBack->ReadByte(); }
+  UInt64 ReadNumber() { return _inByteBack->ReadNumber(); }
+  CNum ReadNum() { return _inByteBack->ReadNum(); }
+  UInt64 ReadID() { return _inByteBack->ReadNumber(); }
+  UInt32 ReadUInt32() { return _inByteBack->ReadUInt32(); }
+  UInt64 ReadUInt64() { return _inByteBack->ReadUInt64(); }
+  void SkeepData(UInt64 size) { _inByteBack->SkeepData(size); }
+  void SkeepData() { _inByteBack->SkeepData(); }
+  void WaitAttribute(UInt64 attribute);
+
+  void ReadArchiveProperties(CInArchiveInfo &archiveInfo);
+  void GetNextFolderItem(CFolder &itemInfo);
+  void ReadHashDigests(int numItems,
+      CRecordVector<bool> &digestsDefined, CRecordVector<UInt32> &digests);
+  
+  void ReadPackInfo(
+      UInt64 &dataOffset,
+      CRecordVector<UInt64> &packSizes,
+      CRecordVector<bool> &packCRCsDefined,
+      CRecordVector<UInt32> &packCRCs);
+  
+  void ReadUnPackInfo(
+      const CObjectVector<CByteBuffer> *dataVector,
+      CObjectVector<CFolder> &folders);
+  
+  void ReadSubStreamsInfo(
+      const CObjectVector<CFolder> &folders,
+      CRecordVector<CNum> &numUnPackStreamsInFolders,
+      CRecordVector<UInt64> &unPackSizes,
+      CRecordVector<bool> &digestsDefined, 
+      CRecordVector<UInt32> &digests);
+
+  void ReadStreamsInfo(
+      const CObjectVector<CByteBuffer> *dataVector,
+      UInt64 &dataOffset,
+      CRecordVector<UInt64> &packSizes,
+      CRecordVector<bool> &packCRCsDefined,
+      CRecordVector<UInt32> &packCRCs,
+      CObjectVector<CFolder> &folders,
+      CRecordVector<CNum> &numUnPackStreamsInFolders,
+      CRecordVector<UInt64> &unPackSizes,
+      CRecordVector<bool> &digestsDefined, 
+      CRecordVector<UInt32> &digests);
+
+
+  void ReadBoolVector(int numItems, CBoolVector &v);
+  void ReadBoolVector2(int numItems, CBoolVector &v);
+  void ReadTime(const CObjectVector<CByteBuffer> &dataVector,
+      CObjectVector<CFileItem> &files, UInt32 type);
+  HRESULT ReadAndDecodePackedStreams(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      UInt64 baseOffset, UInt64 &dataOffset,
+      CObjectVector<CByteBuffer> &dataVector
+      #ifndef _NO_CRYPTO
+      , ICryptoGetTextPassword *getTextPassword
+      #endif
+      );
+  HRESULT ReadHeader(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      CArchiveDatabaseEx &database
+      #ifndef _NO_CRYPTO
+      ,ICryptoGetTextPassword *getTextPassword
+      #endif
+      );
+  HRESULT ReadDatabase2(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      CArchiveDatabaseEx &database 
+      #ifndef _NO_CRYPTO
+      ,ICryptoGetTextPassword *getTextPassword
+      #endif
+      );
+public:
+  HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive
+  void Close();
+
+  HRESULT ReadDatabase(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      CArchiveDatabaseEx &database 
+      #ifndef _NO_CRYPTO
+      ,ICryptoGetTextPassword *getTextPassword
+      #endif
+      );
+};
+  
+}}
+  
+#endif

+ 184 - 0
lzma/CPP/7zip/Archive/7z/7zItem.h

@@ -0,0 +1,184 @@
+// 7zItem.h
+
+#ifndef __7Z_ITEM_H
+#define __7Z_ITEM_H
+
+#include "../../../Common/Buffer.h"
+#include "../../../Common/MyString.h"
+#include "../../Common/MethodId.h"
+#include "7zHeader.h"
+
+namespace NArchive {
+namespace N7z {
+
+typedef UInt32 CNum;
+const CNum kNumMax     = 0x7FFFFFFF;
+const CNum kNumNoIndex = 0xFFFFFFFF;
+
+struct CCoderInfo
+{
+  CMethodId MethodID;
+  CByteBuffer Properties;
+  CNum NumInStreams;
+  CNum NumOutStreams;
+  bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); }
+};
+
+struct CBindPair
+{
+  CNum InIndex;
+  CNum OutIndex;
+};
+
+struct CFolder
+{
+  CObjectVector<CCoderInfo> Coders;
+  CRecordVector<CBindPair> BindPairs;
+  CRecordVector<CNum> PackStreams;
+  CRecordVector<UInt64> UnPackSizes;
+  UInt32 UnPackCRC;
+  bool UnPackCRCDefined;
+
+  CFolder(): UnPackCRCDefined(false) {}
+
+  UInt64 GetUnPackSize() const // test it
+  { 
+    if (UnPackSizes.IsEmpty())
+      return 0;
+    for (int i = UnPackSizes.Size() - 1; i >= 0; i--)
+      if (FindBindPairForOutStream(i) < 0)
+        return UnPackSizes[i];
+    throw 1;
+  }
+
+  CNum GetNumOutStreams() const
+  {
+    CNum result = 0;
+    for (int i = 0; i < Coders.Size(); i++)
+      result += Coders[i].NumOutStreams;
+    return result;
+  }
+
+  int FindBindPairForInStream(CNum inStreamIndex) const
+  {
+    for(int i = 0; i < BindPairs.Size(); i++)
+      if (BindPairs[i].InIndex == inStreamIndex)
+        return i;
+    return -1;
+  }
+  int FindBindPairForOutStream(CNum outStreamIndex) const
+  {
+    for(int i = 0; i < BindPairs.Size(); i++)
+      if (BindPairs[i].OutIndex == outStreamIndex)
+        return i;
+    return -1;
+  }
+  int FindPackStreamArrayIndex(CNum inStreamIndex) const
+  {
+    for(int i = 0; i < PackStreams.Size(); i++)
+      if (PackStreams[i] == inStreamIndex)
+        return i;
+    return -1;
+  }
+};
+
+typedef FILETIME CArchiveFileTime;
+
+class CFileItem
+{
+public:
+  CArchiveFileTime CreationTime;
+  CArchiveFileTime LastWriteTime;
+  CArchiveFileTime LastAccessTime;
+  UInt64 UnPackSize;
+  UInt64 StartPos;
+  UInt32 Attributes;
+  UInt32 FileCRC;
+  UString Name;
+
+  bool HasStream; // Test it !!! it means that there is 
+                  // stream in some folder. It can be empty stream
+  bool IsDirectory;
+  bool IsAnti;
+  bool IsFileCRCDefined;
+  bool AreAttributesDefined;
+  bool IsCreationTimeDefined;
+  bool IsLastWriteTimeDefined;
+  bool IsLastAccessTimeDefined;
+  bool IsStartPosDefined;
+
+  /*
+  const bool HasStream() const { 
+      return !IsDirectory && !IsAnti && UnPackSize != 0; }
+  */
+  CFileItem(): 
+    HasStream(true),
+    IsDirectory(false),
+    IsAnti(false),
+    IsFileCRCDefined(false),
+    AreAttributesDefined(false), 
+    IsCreationTimeDefined(false), 
+    IsLastWriteTimeDefined(false), 
+    IsLastAccessTimeDefined(false),
+    IsStartPosDefined(false)
+      {}
+  void SetAttributes(UInt32 attributes) 
+  { 
+    AreAttributesDefined = true;
+    Attributes = attributes;
+  }
+  void SetCreationTime(const CArchiveFileTime &creationTime) 
+  { 
+    IsCreationTimeDefined = true;
+    CreationTime = creationTime;
+  }
+  void SetLastWriteTime(const CArchiveFileTime &lastWriteTime) 
+  {
+    IsLastWriteTimeDefined = true;
+    LastWriteTime = lastWriteTime;
+  }
+  void SetLastAccessTime(const CArchiveFileTime &lastAccessTime) 
+  { 
+    IsLastAccessTimeDefined = true;
+    LastAccessTime = lastAccessTime;
+  }
+};
+
+struct CArchiveDatabase
+{
+  CRecordVector<UInt64> PackSizes;
+  CRecordVector<bool> PackCRCsDefined;
+  CRecordVector<UInt32> PackCRCs;
+  CObjectVector<CFolder> Folders;
+  CRecordVector<CNum> NumUnPackStreamsVector;
+  CObjectVector<CFileItem> Files;
+  void Clear()
+  {
+    PackSizes.Clear();
+    PackCRCsDefined.Clear();
+    PackCRCs.Clear();
+    Folders.Clear();
+    NumUnPackStreamsVector.Clear();
+    Files.Clear();
+  }
+  bool IsEmpty() const
+  {
+    return (PackSizes.IsEmpty() && 
+      PackCRCsDefined.IsEmpty() && 
+      PackCRCs.IsEmpty() && 
+      Folders.IsEmpty() && 
+      NumUnPackStreamsVector.IsEmpty() && 
+      Files.IsEmpty());
+  }
+  bool IsSolid() const
+  {
+    for (int i = 0; i < NumUnPackStreamsVector.Size(); i++)
+      if (NumUnPackStreamsVector[i] > 1)
+        return true;
+    return false;
+  }
+};
+
+}}
+
+#endif

+ 1026 - 0
lzma/CPP/7zip/Archive/7z/7zOut.cpp

@@ -0,0 +1,1026 @@
+// 7zOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/AutoPtr.h"
+#include "../../Common/StreamObjects.h"
+
+#include "7zOut.h"
+
+extern "C" 
+{ 
+#include "../../../../C/7zCrc.h"
+}
+
+static HRESULT WriteBytes(ISequentialOutStream *stream, const void *data, size_t size)
+{
+  while (size > 0)
+  {
+    UInt32 curSize = (UInt32)MyMin(size, (size_t)0xFFFFFFFF);
+    UInt32 processedSize;
+    RINOK(stream->Write(data, curSize, &processedSize));
+    if(processedSize == 0)
+      return E_FAIL;
+    data = (const void *)((const Byte *)data + processedSize);
+    size -= processedSize;
+  }
+  return S_OK;
+}
+
+namespace NArchive {
+namespace N7z {
+
+HRESULT COutArchive::WriteDirect(const void *data, UInt32 size)
+{
+  return ::WriteBytes(SeqStream, data, size);
+}
+
+UInt32 CrcUpdateUInt32(UInt32 crc, UInt32 value)
+{
+  for (int i = 0; i < 4; i++, value >>= 8)
+    crc = CRC_UPDATE_BYTE(crc, (Byte)value);
+  return crc;
+}
+
+UInt32 CrcUpdateUInt64(UInt32 crc, UInt64 value)
+{
+  for (int i = 0; i < 8; i++, value >>= 8)
+    crc = CRC_UPDATE_BYTE(crc, (Byte)value);
+  return crc;
+}
+
+HRESULT COutArchive::WriteDirectUInt32(UInt32 value)
+{
+  for (int i = 0; i < 4; i++)
+  {
+    RINOK(WriteDirectByte((Byte)value));
+    value >>= 8;
+  }
+  return S_OK;
+}
+
+HRESULT COutArchive::WriteDirectUInt64(UInt64 value)
+{
+  for (int i = 0; i < 8; i++)
+  {
+    RINOK(WriteDirectByte((Byte)value));
+    value >>= 8;
+  }
+  return S_OK;
+}
+
+HRESULT COutArchive::WriteSignature()
+{
+  RINOK(WriteDirect(kSignature, kSignatureSize));
+  RINOK(WriteDirectByte(kMajorVersion));
+  return WriteDirectByte(2);
+}
+
+#ifdef _7Z_VOL
+HRESULT COutArchive::WriteFinishSignature()
+{
+  RINOK(WriteDirect(kFinishSignature, kSignatureSize));
+  CArchiveVersion av;
+  av.Major = kMajorVersion;
+  av.Minor = 2;
+  RINOK(WriteDirectByte(av.Major));
+  return WriteDirectByte(av.Minor);
+}
+#endif
+
+HRESULT COutArchive::WriteStartHeader(const CStartHeader &h)
+{
+  UInt32 crc = CRC_INIT_VAL;
+  crc = CrcUpdateUInt64(crc, h.NextHeaderOffset);
+  crc = CrcUpdateUInt64(crc, h.NextHeaderSize);
+  crc = CrcUpdateUInt32(crc, h.NextHeaderCRC);
+  RINOK(WriteDirectUInt32(CRC_GET_DIGEST(crc)));
+  RINOK(WriteDirectUInt64(h.NextHeaderOffset));
+  RINOK(WriteDirectUInt64(h.NextHeaderSize));
+  return WriteDirectUInt32(h.NextHeaderCRC);
+}
+
+#ifdef _7Z_VOL
+HRESULT COutArchive::WriteFinishHeader(const CFinishHeader &h)
+{
+  CCRC crc;
+  crc.UpdateUInt64(h.NextHeaderOffset);
+  crc.UpdateUInt64(h.NextHeaderSize);
+  crc.UpdateUInt32(h.NextHeaderCRC);
+  crc.UpdateUInt64(h.ArchiveStartOffset);
+  crc.UpdateUInt64(h.AdditionalStartBlockSize);
+  RINOK(WriteDirectUInt32(crc.GetDigest()));
+  RINOK(WriteDirectUInt64(h.NextHeaderOffset));
+  RINOK(WriteDirectUInt64(h.NextHeaderSize));
+  RINOK(WriteDirectUInt32(h.NextHeaderCRC));
+  RINOK(WriteDirectUInt64(h.ArchiveStartOffset));
+  return WriteDirectUInt64(h.AdditionalStartBlockSize);
+}
+#endif
+
+HRESULT COutArchive::Create(ISequentialOutStream *stream, bool endMarker)
+{
+  Close();
+  #ifdef _7Z_VOL
+  // endMarker = false;
+  _endMarker = endMarker;
+  #endif
+  SeqStream = stream;
+  if (!endMarker)
+  {
+    SeqStream.QueryInterface(IID_IOutStream, &Stream);
+    if (!Stream)
+    {
+      return E_NOTIMPL;
+      // endMarker = true;
+    }
+  }
+  #ifdef _7Z_VOL
+  if (endMarker)
+  {
+    /*
+    CStartHeader sh;
+    sh.NextHeaderOffset = (UInt32)(Int32)-1;
+    sh.NextHeaderSize = (UInt32)(Int32)-1;
+    sh.NextHeaderCRC = 0;
+    WriteStartHeader(sh);
+    */
+  }
+  else
+  #endif
+  {
+    if (!Stream)
+      return E_FAIL;
+    RINOK(WriteSignature());
+    RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_prefixHeaderPos));
+  }
+  return S_OK;
+}
+
+void COutArchive::Close()
+{
+  SeqStream.Release();
+  Stream.Release();
+}
+
+HRESULT COutArchive::SkeepPrefixArchiveHeader()
+{
+  #ifdef _7Z_VOL
+  if (_endMarker)
+    return S_OK;
+  #endif
+  return Stream->Seek(24, STREAM_SEEK_CUR, NULL);
+}
+
+HRESULT COutArchive::WriteBytes(const void *data, size_t size)
+{
+  if (_mainMode)
+  {
+    if (_dynamicMode)
+      _dynamicBuffer.Write(data, size);
+    else
+      _outByte.WriteBytes(data, size);
+    _crc = CrcUpdate(_crc, data, size);
+  }
+  else
+  {
+    if (_countMode)
+      _countSize += size;
+    else
+      RINOK(_outByte2.Write(data, size));
+  }
+  return S_OK;
+}
+
+HRESULT COutArchive::WriteBytes(const CByteBuffer &data)
+{
+  return WriteBytes(data, data.GetCapacity());
+}
+
+HRESULT COutArchive::WriteByte(Byte b)
+{
+  return WriteBytes(&b, 1);
+}
+
+HRESULT COutArchive::WriteUInt32(UInt32 value)
+{
+  for (int i = 0; i < 4; i++)
+  {
+    RINOK(WriteByte((Byte)value));
+    value >>= 8;
+  }
+  return S_OK;
+}
+
+HRESULT COutArchive::WriteNumber(UInt64 value)
+{
+  Byte firstByte = 0;
+  Byte mask = 0x80;
+  int i;
+  for (i = 0; i < 8; i++)
+  {
+    if (value < ((UInt64(1) << ( 7  * (i + 1)))))
+    {
+      firstByte |= Byte(value >> (8 * i));
+      break;
+    }
+    firstByte |= mask;
+    mask >>= 1;
+  }
+  RINOK(WriteByte(firstByte));
+  for (;i > 0; i--)
+  {
+    RINOK(WriteByte((Byte)value));
+    value >>= 8;
+  }
+  return S_OK;
+}
+
+#ifdef _7Z_VOL
+static UInt32 GetBigNumberSize(UInt64 value)
+{
+  int i;
+  for (i = 0; i < 8; i++)
+    if (value < ((UInt64(1) << ( 7  * (i + 1)))))
+      break;
+  return 1 + i;
+}
+
+UInt32 COutArchive::GetVolHeadersSize(UInt64 dataSize, int nameLength, bool props)
+{
+  UInt32 result = GetBigNumberSize(dataSize) * 2 + 41;
+  if (nameLength != 0)
+  {
+    nameLength = (nameLength + 1) * 2;
+    result += nameLength + GetBigNumberSize(nameLength) + 2;
+  }
+  if (props)
+  {
+    result += 20;
+  }
+  if (result >= 128)
+    result++;
+  result += kSignatureSize + 2 + kFinishHeaderSize;
+  return result;
+}
+
+UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props)
+{
+  UInt32 headersSizeBase = COutArchive::GetVolHeadersSize(1, nameLength, props);
+  int testSize;
+  if (volSize > headersSizeBase)
+    testSize = volSize - headersSizeBase;
+  else
+    testSize = 1;
+  UInt32 headersSize = COutArchive::GetVolHeadersSize(testSize, nameLength, props);
+  UInt64 pureSize = 1;
+  if (volSize > headersSize)
+    pureSize = volSize - headersSize;
+  return pureSize;
+}
+#endif
+
+HRESULT COutArchive::WriteFolder(const CFolder &folder)
+{
+  RINOK(WriteNumber(folder.Coders.Size()));
+  int i;
+  for (i = 0; i < folder.Coders.Size(); i++)
+  {
+    const CCoderInfo &coder = folder.Coders[i];
+    {
+      size_t propertiesSize = coder.Properties.GetCapacity();
+      
+      UInt64 id = coder.MethodID; 
+      int idSize;
+      for (idSize = 1; idSize < sizeof(id); idSize++)
+        if ((id >> (8 * idSize)) == 0)
+          break;
+      BYTE longID[15];
+      for (int t = idSize - 1; t >= 0 ; t--, id >>= 8)
+        longID[t] = (Byte)(id & 0xFF);
+      Byte b;
+      b = (Byte)(idSize & 0xF);
+      bool isComplex = !coder.IsSimpleCoder();
+      b |= (isComplex ? 0x10 : 0);
+      b |= ((propertiesSize != 0) ? 0x20 : 0 );
+      RINOK(WriteByte(b));
+      RINOK(WriteBytes(longID, idSize));
+      if (isComplex)
+      {
+        RINOK(WriteNumber(coder.NumInStreams));
+        RINOK(WriteNumber(coder.NumOutStreams));
+      }
+      if (propertiesSize == 0)
+        continue;
+      RINOK(WriteNumber(propertiesSize));
+      RINOK(WriteBytes(coder.Properties, propertiesSize));
+    }
+  }
+  for (i = 0; i < folder.BindPairs.Size(); i++)
+  {
+    const CBindPair &bindPair = folder.BindPairs[i];
+    RINOK(WriteNumber(bindPair.InIndex));
+    RINOK(WriteNumber(bindPair.OutIndex));
+  }
+  if (folder.PackStreams.Size() > 1)
+    for (i = 0; i < folder.PackStreams.Size(); i++)
+    {
+      RINOK(WriteNumber(folder.PackStreams[i]));
+    }
+  return S_OK;
+}
+
+HRESULT COutArchive::WriteBoolVector(const CBoolVector &boolVector)
+{
+  Byte b = 0;
+  Byte mask = 0x80;
+  for(int i = 0; i < boolVector.Size(); i++)
+  {
+    if (boolVector[i])
+      b |= mask;
+    mask >>= 1;
+    if (mask == 0)
+    {
+      RINOK(WriteByte(b));
+      mask = 0x80;
+      b = 0;
+    }
+  }
+  if (mask != 0x80)
+  {
+    RINOK(WriteByte(b));
+  }
+  return S_OK;
+}
+
+
+HRESULT COutArchive::WriteHashDigests(
+    const CRecordVector<bool> &digestsDefined,
+    const CRecordVector<UInt32> &digests)
+{
+  int numDefined = 0;
+  int i;
+  for(i = 0; i < digestsDefined.Size(); i++)
+    if (digestsDefined[i])
+      numDefined++;
+  if (numDefined == 0)
+    return S_OK;
+
+  RINOK(WriteByte(NID::kCRC));
+  if (numDefined == digestsDefined.Size())
+  {
+    RINOK(WriteByte(1));
+  }
+  else
+  {
+    RINOK(WriteByte(0));
+    RINOK(WriteBoolVector(digestsDefined));
+  }
+  for(i = 0; i < digests.Size(); i++)
+  {
+    if(digestsDefined[i])
+      RINOK(WriteUInt32(digests[i]));
+  }
+  return S_OK;
+}
+
+HRESULT COutArchive::WritePackInfo(
+    UInt64 dataOffset,
+    const CRecordVector<UInt64> &packSizes,
+    const CRecordVector<bool> &packCRCsDefined,
+    const CRecordVector<UInt32> &packCRCs)
+{
+  if (packSizes.IsEmpty())
+    return S_OK;
+  RINOK(WriteByte(NID::kPackInfo));
+  RINOK(WriteNumber(dataOffset));
+  RINOK(WriteNumber(packSizes.Size()));
+  RINOK(WriteByte(NID::kSize));
+  for(int i = 0; i < packSizes.Size(); i++)
+    RINOK(WriteNumber(packSizes[i]));
+
+  RINOK(WriteHashDigests(packCRCsDefined, packCRCs));
+  
+  return WriteByte(NID::kEnd);
+}
+
+HRESULT COutArchive::WriteUnPackInfo(const CObjectVector<CFolder> &folders)
+{
+  if (folders.IsEmpty())
+    return S_OK;
+
+  RINOK(WriteByte(NID::kUnPackInfo));
+
+  RINOK(WriteByte(NID::kFolder));
+  RINOK(WriteNumber(folders.Size()));
+  {
+    RINOK(WriteByte(0));
+    for(int i = 0; i < folders.Size(); i++)
+      RINOK(WriteFolder(folders[i]));
+  }
+  
+  RINOK(WriteByte(NID::kCodersUnPackSize));
+  int i;
+  for(i = 0; i < folders.Size(); i++)
+  {
+    const CFolder &folder = folders[i];
+    for (int j = 0; j < folder.UnPackSizes.Size(); j++)
+      RINOK(WriteNumber(folder.UnPackSizes[j]));
+  }
+
+  CRecordVector<bool> unPackCRCsDefined;
+  CRecordVector<UInt32> unPackCRCs;
+  for(i = 0; i < folders.Size(); i++)
+  {
+    const CFolder &folder = folders[i];
+    unPackCRCsDefined.Add(folder.UnPackCRCDefined);
+    unPackCRCs.Add(folder.UnPackCRC);
+  }
+  RINOK(WriteHashDigests(unPackCRCsDefined, unPackCRCs));
+
+  return WriteByte(NID::kEnd);
+}
+
+HRESULT COutArchive::WriteSubStreamsInfo(
+    const CObjectVector<CFolder> &folders,
+    const CRecordVector<CNum> &numUnPackStreamsInFolders,
+    const CRecordVector<UInt64> &unPackSizes,
+    const CRecordVector<bool> &digestsDefined,
+    const CRecordVector<UInt32> &digests)
+{
+  RINOK(WriteByte(NID::kSubStreamsInfo));
+
+  int i;
+  for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
+  {
+    if (numUnPackStreamsInFolders[i] != 1)
+    {
+      RINOK(WriteByte(NID::kNumUnPackStream));
+      for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
+        RINOK(WriteNumber(numUnPackStreamsInFolders[i]));
+      break;
+    }
+  }
+ 
+
+  bool needFlag = true;
+  CNum index = 0;
+  for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
+    for (CNum j = 0; j < numUnPackStreamsInFolders[i]; j++)
+    {
+      if (j + 1 != numUnPackStreamsInFolders[i])
+      {
+        if (needFlag)
+          RINOK(WriteByte(NID::kSize));
+        needFlag = false;
+        RINOK(WriteNumber(unPackSizes[index]));
+      }
+      index++;
+    }
+
+  CRecordVector<bool> digestsDefined2;
+  CRecordVector<UInt32> digests2;
+
+  int digestIndex = 0;
+  for (i = 0; i < folders.Size(); i++)
+  {
+    int numSubStreams = (int)numUnPackStreamsInFolders[i];
+    if (numSubStreams == 1 && folders[i].UnPackCRCDefined)
+      digestIndex++;
+    else
+      for (int j = 0; j < numSubStreams; j++, digestIndex++)
+      {
+        digestsDefined2.Add(digestsDefined[digestIndex]);
+        digests2.Add(digests[digestIndex]);
+      }
+  }
+  RINOK(WriteHashDigests(digestsDefined2, digests2));
+  return WriteByte(NID::kEnd);
+}
+
+HRESULT COutArchive::WriteTime(
+    const CObjectVector<CFileItem> &files, Byte type)
+{
+  /////////////////////////////////////////////////
+  // CreationTime
+  CBoolVector boolVector;
+  boolVector.Reserve(files.Size());
+  bool thereAreDefined = false;
+  bool allDefined = true;
+  int i;
+  for(i = 0; i < files.Size(); i++)
+  {
+    const CFileItem &item = files[i];
+    bool defined;
+    switch(type)
+    {
+      case NID::kCreationTime:
+        defined = item.IsCreationTimeDefined;
+        break;
+      case NID::kLastWriteTime:
+        defined = item.IsLastWriteTimeDefined;
+        break;
+      case NID::kLastAccessTime:
+        defined = item.IsLastAccessTimeDefined;
+        break;
+      default:
+        throw 1;
+    }
+    boolVector.Add(defined);
+    thereAreDefined = (thereAreDefined || defined);
+    allDefined = (allDefined && defined);
+  }
+  if (!thereAreDefined)
+    return S_OK;
+  RINOK(WriteByte(type));
+  size_t dataSize = 1 + 1;
+    dataSize += files.Size() * 8;
+  if (allDefined)
+  {
+    RINOK(WriteNumber(dataSize));
+    WriteByte(1);
+  }
+  else
+  {
+    RINOK(WriteNumber(1 + (boolVector.Size() + 7) / 8 + dataSize));
+    WriteByte(0);
+    RINOK(WriteBoolVector(boolVector));
+  }
+  RINOK(WriteByte(0));
+  for(i = 0; i < files.Size(); i++)
+  {
+    if (boolVector[i])
+    {
+      const CFileItem &item = files[i];
+      CArchiveFileTime timeValue;
+      timeValue.dwLowDateTime = 0;
+      timeValue.dwHighDateTime = 0;
+      switch(type)
+      {
+        case NID::kCreationTime:
+          timeValue = item.CreationTime;
+          break;
+        case NID::kLastWriteTime:
+          timeValue = item.LastWriteTime;
+          break;
+        case NID::kLastAccessTime:
+          timeValue = item.LastAccessTime;
+          break;
+      }
+      RINOK(WriteUInt32(timeValue.dwLowDateTime));
+      RINOK(WriteUInt32(timeValue.dwHighDateTime));
+    }
+  }
+  return S_OK;
+}
+
+HRESULT COutArchive::EncodeStream(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    CEncoder &encoder, const Byte *data, size_t dataSize,
+    CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders)
+{
+  CSequentialInStreamImp *streamSpec = new CSequentialInStreamImp;
+  CMyComPtr<ISequentialInStream> stream = streamSpec;
+  streamSpec->Init(data, dataSize);
+  CFolder folderItem;
+  folderItem.UnPackCRCDefined = true;
+  folderItem.UnPackCRC = CrcCalc(data, dataSize);
+  UInt64 dataSize64 = dataSize;
+  RINOK(encoder.Encode(
+      EXTERNAL_CODECS_LOC_VARS
+      stream, NULL, &dataSize64, folderItem, SeqStream, packSizes, NULL))
+  folders.Add(folderItem);
+  return S_OK;
+}
+
+HRESULT COutArchive::EncodeStream(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    CEncoder &encoder, const CByteBuffer &data, 
+    CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders)
+{
+  return EncodeStream(
+      EXTERNAL_CODECS_LOC_VARS
+      encoder, data, data.GetCapacity(), packSizes, folders);
+}
+
+static void WriteUInt32ToBuffer(Byte *data, UInt32 value)
+{
+  for (int i = 0; i < 4; i++)
+  {
+    *data++ = (Byte)value;
+    value >>= 8;
+  }
+}
+
+static void WriteUInt64ToBuffer(Byte *data, UInt64 value)
+{
+  for (int i = 0; i < 8; i++)
+  {
+    *data++ = (Byte)value;
+    value >>= 8;
+  }
+}
+
+
+HRESULT COutArchive::WriteHeader(
+    const CArchiveDatabase &database,
+    const CHeaderOptions &headerOptions,
+    UInt64 &headerOffset)
+{
+  int i;
+  
+  /////////////////////////////////
+  // Names
+
+  CNum numDefinedNames = 0;
+  size_t namesDataSize = 0;
+  for(i = 0; i < database.Files.Size(); i++)
+  {
+    const UString &name = database.Files[i].Name;
+    if (!name.IsEmpty())
+      numDefinedNames++;
+    namesDataSize += (name.Length() + 1) * 2;
+  }
+
+  CByteBuffer namesData;
+  if (numDefinedNames > 0)
+  {
+    namesData.SetCapacity((size_t)namesDataSize);
+    size_t pos = 0;
+    for(int i = 0; i < database.Files.Size(); i++)
+    {
+      const UString &name = database.Files[i].Name;
+      for (int t = 0; t < name.Length(); t++)
+      {
+        wchar_t c = name[t];
+        namesData[pos++] = Byte(c);
+        namesData[pos++] = Byte(c >> 8);
+      }
+      namesData[pos++] = 0;
+      namesData[pos++] = 0;
+    }
+  }
+
+  /////////////////////////////////
+  // Write Attributes
+  CBoolVector attributesBoolVector;
+  attributesBoolVector.Reserve(database.Files.Size());
+  int numDefinedAttributes = 0;
+  for(i = 0; i < database.Files.Size(); i++)
+  {
+    bool defined = database.Files[i].AreAttributesDefined;
+    attributesBoolVector.Add(defined);
+    if (defined)
+      numDefinedAttributes++;
+  }
+
+  CByteBuffer attributesData;
+  if (numDefinedAttributes > 0)
+  {
+    attributesData.SetCapacity(numDefinedAttributes * 4);
+    size_t pos = 0;
+    for(i = 0; i < database.Files.Size(); i++)
+    {
+      const CFileItem &file = database.Files[i];
+      if (file.AreAttributesDefined)
+      {
+        WriteUInt32ToBuffer(attributesData + pos, file.Attributes);
+        pos += 4;
+      }
+    }
+  }
+
+  /////////////////////////////////
+  // Write StartPos
+  CBoolVector startsBoolVector;
+  startsBoolVector.Reserve(database.Files.Size());
+  int numDefinedStarts = 0;
+  for(i = 0; i < database.Files.Size(); i++)
+  {
+    bool defined = database.Files[i].IsStartPosDefined;
+    startsBoolVector.Add(defined);
+    if (defined)
+      numDefinedStarts++;
+  }
+
+  CByteBuffer startsData;
+  if (numDefinedStarts > 0)
+  {
+    startsData.SetCapacity(numDefinedStarts * 8);
+    size_t pos = 0;
+    for(i = 0; i < database.Files.Size(); i++)
+    {
+      const CFileItem &file = database.Files[i];
+      if (file.IsStartPosDefined)
+      {
+        WriteUInt64ToBuffer(startsData + pos, file.StartPos);
+        pos += 8;
+      }
+    }
+  }
+  
+  /////////////////////////////////
+  // Write Last Write Time
+  // /*
+  CNum numDefinedLastWriteTimes = 0;
+  for(i = 0; i < database.Files.Size(); i++)
+    if (database.Files[i].IsLastWriteTimeDefined)
+      numDefinedLastWriteTimes++;
+
+  if (numDefinedLastWriteTimes > 0)
+  {
+    CByteBuffer lastWriteTimeData;
+    lastWriteTimeData.SetCapacity(numDefinedLastWriteTimes * 8);
+    size_t pos = 0;
+    for(i = 0; i < database.Files.Size(); i++)
+    {
+      const CFileItem &file = database.Files[i];
+      if (file.IsLastWriteTimeDefined)
+      {
+        WriteUInt32ToBuffer(lastWriteTimeData + pos, file.LastWriteTime.dwLowDateTime);
+        pos += 4;
+        WriteUInt32ToBuffer(lastWriteTimeData + pos, file.LastWriteTime.dwHighDateTime);
+        pos += 4;
+      }
+    }
+  }
+  // */
+  
+
+  UInt64 packedSize = 0;
+  for(i = 0; i < database.PackSizes.Size(); i++)
+    packedSize += database.PackSizes[i];
+
+  headerOffset = packedSize;
+
+  _mainMode = true;
+
+  _outByte.SetStream(SeqStream);
+  _outByte.Init();
+  _crc = CRC_INIT_VAL;
+
+
+  RINOK(WriteByte(NID::kHeader));
+
+  // Archive Properties
+
+  if (database.Folders.Size() > 0)
+  {
+    RINOK(WriteByte(NID::kMainStreamsInfo));
+    RINOK(WritePackInfo(0, database.PackSizes, 
+        database.PackCRCsDefined,
+        database.PackCRCs));
+
+    RINOK(WriteUnPackInfo(database.Folders));
+
+    CRecordVector<UInt64> unPackSizes;
+    CRecordVector<bool> digestsDefined;
+    CRecordVector<UInt32> digests;
+    for (i = 0; i < database.Files.Size(); i++)
+    {
+      const CFileItem &file = database.Files[i];
+      if (!file.HasStream)
+        continue;
+      unPackSizes.Add(file.UnPackSize);
+      digestsDefined.Add(file.IsFileCRCDefined);
+      digests.Add(file.FileCRC);
+    }
+
+    RINOK(WriteSubStreamsInfo(
+        database.Folders,
+        database.NumUnPackStreamsVector,
+        unPackSizes,
+        digestsDefined,
+        digests));
+    RINOK(WriteByte(NID::kEnd));
+  }
+
+  if (database.Files.IsEmpty())
+  {
+    RINOK(WriteByte(NID::kEnd));
+    return _outByte.Flush();
+  }
+
+  RINOK(WriteByte(NID::kFilesInfo));
+  RINOK(WriteNumber(database.Files.Size()));
+
+  CBoolVector emptyStreamVector;
+  emptyStreamVector.Reserve(database.Files.Size());
+  int numEmptyStreams = 0;
+  for(i = 0; i < database.Files.Size(); i++)
+    if (database.Files[i].HasStream)
+      emptyStreamVector.Add(false);
+    else
+    {
+      emptyStreamVector.Add(true);
+      numEmptyStreams++;
+    }
+  if (numEmptyStreams > 0)
+  {
+    RINOK(WriteByte(NID::kEmptyStream));
+    RINOK(WriteNumber((emptyStreamVector.Size() + 7) / 8));
+    RINOK(WriteBoolVector(emptyStreamVector));
+
+    CBoolVector emptyFileVector, antiVector;
+    emptyFileVector.Reserve(numEmptyStreams);
+    antiVector.Reserve(numEmptyStreams);
+    CNum numEmptyFiles = 0, numAntiItems = 0;
+    for(i = 0; i < database.Files.Size(); i++)
+    {
+      const CFileItem &file = database.Files[i];
+      if (!file.HasStream)
+      {
+        emptyFileVector.Add(!file.IsDirectory);
+        if (!file.IsDirectory)
+          numEmptyFiles++;
+        antiVector.Add(file.IsAnti);
+        if (file.IsAnti)
+          numAntiItems++;
+      }
+    }
+
+    if (numEmptyFiles > 0)
+    {
+      RINOK(WriteByte(NID::kEmptyFile));
+      RINOK(WriteNumber((emptyFileVector.Size() + 7) / 8));
+      RINOK(WriteBoolVector(emptyFileVector));
+    }
+
+    if (numAntiItems > 0)
+    {
+      RINOK(WriteByte(NID::kAnti));
+      RINOK(WriteNumber((antiVector.Size() + 7) / 8));
+      RINOK(WriteBoolVector(antiVector));
+    }
+  }
+
+  if (numDefinedNames > 0)
+  {
+    /////////////////////////////////////////////////
+    RINOK(WriteByte(NID::kName));
+    {
+      RINOK(WriteNumber(1 + namesData.GetCapacity()));
+      RINOK(WriteByte(0));
+      RINOK(WriteBytes(namesData));
+    }
+
+  }
+
+  if (headerOptions.WriteCreated)
+  {
+    RINOK(WriteTime(database.Files, NID::kCreationTime));
+  }
+  if (headerOptions.WriteModified)
+  {
+    RINOK(WriteTime(database.Files, NID::kLastWriteTime));
+  }
+  if (headerOptions.WriteAccessed)
+  {
+    RINOK(WriteTime(database.Files, NID::kLastAccessTime));
+  }
+
+  if (numDefinedAttributes > 0)
+  {
+    RINOK(WriteByte(NID::kWinAttributes));
+    size_t size = 2;
+    if (numDefinedAttributes != database.Files.Size())
+      size += (attributesBoolVector.Size() + 7) / 8 + 1;
+      size += attributesData.GetCapacity();
+
+    RINOK(WriteNumber(size));
+    if (numDefinedAttributes == database.Files.Size())
+    {
+      RINOK(WriteByte(1));
+    }
+    else
+    {
+      RINOK(WriteByte(0));
+      RINOK(WriteBoolVector(attributesBoolVector));
+    }
+
+    {
+      RINOK(WriteByte(0));
+      RINOK(WriteBytes(attributesData));
+    }
+  }
+
+  if (numDefinedStarts > 0)
+  {
+    RINOK(WriteByte(NID::kStartPos));
+    size_t size = 2;
+    if (numDefinedStarts != database.Files.Size())
+      size += (startsBoolVector.Size() + 7) / 8 + 1;
+      size += startsData.GetCapacity();
+
+    RINOK(WriteNumber(size));
+    if (numDefinedStarts == database.Files.Size())
+    {
+      RINOK(WriteByte(1));
+    }
+    else
+    {
+      RINOK(WriteByte(0));
+      RINOK(WriteBoolVector(startsBoolVector));
+    }
+
+    {
+      RINOK(WriteByte(0));
+      RINOK(WriteBytes(startsData));
+    }
+  }
+
+  RINOK(WriteByte(NID::kEnd)); // for files
+  RINOK(WriteByte(NID::kEnd)); // for headers
+
+  return _outByte.Flush();
+}
+
+HRESULT COutArchive::WriteDatabase(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    const CArchiveDatabase &database,
+    const CCompressionMethodMode *options, 
+    const CHeaderOptions &headerOptions)
+{
+  UInt64 headerOffset;
+  UInt32 headerCRC;
+  UInt64 headerSize;
+  if (database.IsEmpty())
+  {
+    headerSize = 0;
+    headerOffset = 0;
+    headerCRC = CrcCalc(0, 0);
+  }
+  else
+  {
+    _dynamicBuffer.Init();
+    _dynamicMode = false;
+
+    if (options != 0)
+      if (options->IsEmpty())
+        options = 0;
+    if (options != 0)
+      if (options->PasswordIsDefined || headerOptions.CompressMainHeader)
+        _dynamicMode = true;
+    RINOK(WriteHeader(database, headerOptions, headerOffset));
+
+    if (_dynamicMode)
+    {
+      CCompressionMethodMode encryptOptions;
+      encryptOptions.PasswordIsDefined = options->PasswordIsDefined;
+      encryptOptions.Password = options->Password;
+      CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions);
+      CRecordVector<UInt64> packSizes;
+      CObjectVector<CFolder> folders;
+      RINOK(EncodeStream(
+          EXTERNAL_CODECS_LOC_VARS
+          encoder, _dynamicBuffer, 
+          _dynamicBuffer.GetSize(), packSizes, folders));
+      _dynamicMode = false;
+      _mainMode = true;
+      
+      _outByte.SetStream(SeqStream);
+      _outByte.Init();
+      _crc = CRC_INIT_VAL;
+      
+      if (folders.Size() == 0)
+        throw 1;
+
+      RINOK(WriteID(NID::kEncodedHeader));
+      RINOK(WritePackInfo(headerOffset, packSizes, 
+        CRecordVector<bool>(), CRecordVector<UInt32>()));
+      RINOK(WriteUnPackInfo(folders));
+      RINOK(WriteByte(NID::kEnd));
+      for (int i = 0; i < packSizes.Size(); i++)
+        headerOffset += packSizes[i];
+      RINOK(_outByte.Flush());
+    }
+    headerCRC = CRC_GET_DIGEST(_crc);
+    headerSize = _outByte.GetProcessedSize();
+  }
+  #ifdef _7Z_VOL
+  if (_endMarker)
+  {
+    CFinishHeader h;
+    h.NextHeaderSize = headerSize;
+    h.NextHeaderCRC = headerCRC;
+    h.NextHeaderOffset = 
+        UInt64(0) - (headerSize + 
+        4 + kFinishHeaderSize);
+    h.ArchiveStartOffset = h.NextHeaderOffset - headerOffset;
+    h.AdditionalStartBlockSize = 0;
+    RINOK(WriteFinishHeader(h));
+    return WriteFinishSignature();
+  }
+  else
+  #endif
+  {
+    CStartHeader h;
+    h.NextHeaderSize = headerSize;
+    h.NextHeaderCRC = headerCRC;
+    h.NextHeaderOffset = headerOffset;
+    RINOK(Stream->Seek(_prefixHeaderPos, STREAM_SEEK_SET, NULL));
+    return WriteStartHeader(h);
+  }
+}
+
+}}

+ 193 - 0
lzma/CPP/7zip/Archive/7z/7zOut.h

@@ -0,0 +1,193 @@
+// 7z/Out.h
+
+#ifndef __7Z_OUT_H
+#define __7Z_OUT_H
+
+#include "7zHeader.h"
+#include "7zItem.h"
+#include "7zCompressionMode.h"
+#include "7zEncode.h"
+
+#include "../../Common/OutBuffer.h"
+#include "../../../Common/DynamicBuffer.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CWriteBufferLoc
+{
+  Byte *_data;
+  size_t _size;
+  size_t _pos;
+public:
+  CWriteBufferLoc(): _size(0), _pos(0) {}
+  void Init(Byte *data, size_t size)  
+  { 
+    _pos = 0;
+    _data = data;
+    _size = size; 
+  }
+  HRESULT Write(const void *data, size_t size)
+  {
+    if (_pos + size > _size)
+      return E_FAIL;
+    memmove(_data + _pos, data, size);
+    _pos += size;
+    return S_OK; 
+  }
+};
+
+class CWriteDynamicBuffer
+{
+  CByteDynamicBuffer _buffer;
+  size_t _pos;
+public:
+  CWriteDynamicBuffer(): _pos(0) {}
+  void Init()  
+  { 
+    _pos = 0;
+  }
+  void Write(const void *data, size_t size)
+  {
+    if (_pos + size > _buffer.GetCapacity())
+      _buffer.EnsureCapacity(_pos + size);
+    memmove(((Byte *)_buffer) +_pos, data, size);
+    _pos += size;
+  }
+  operator Byte *() { return (Byte *)_buffer; };
+  operator const Byte *() const { return (const Byte *)_buffer; };
+  size_t GetSize() const { return _pos; }
+};
+
+struct CHeaderOptions
+{
+  // bool UseAdditionalHeaderStreams;
+  bool CompressMainHeader;
+  bool WriteModified;
+  bool WriteCreated;
+  bool WriteAccessed;
+
+  CHeaderOptions(): 
+      // UseAdditionalHeaderStreams(false), 
+      CompressMainHeader(true),
+      WriteModified(true),
+      WriteCreated(false),
+      WriteAccessed(false) {} 
+};
+
+class COutArchive
+{
+  UInt64 _prefixHeaderPos;
+
+  HRESULT WriteDirect(const void *data, UInt32 size);
+  HRESULT WriteDirectByte(Byte b) { return WriteDirect(&b, 1); }
+  HRESULT WriteDirectUInt32(UInt32 value);
+  HRESULT WriteDirectUInt64(UInt64 value);
+  
+  HRESULT WriteBytes(const void *data, size_t size);
+  HRESULT WriteBytes(const CByteBuffer &data);
+  HRESULT WriteByte(Byte b);
+  HRESULT WriteUInt32(UInt32 value);
+  HRESULT WriteNumber(UInt64 value);
+  HRESULT WriteID(UInt64 value) { return WriteNumber(value); }
+
+  HRESULT WriteFolder(const CFolder &folder);
+  HRESULT WriteFileHeader(const CFileItem &itemInfo);
+  HRESULT WriteBoolVector(const CBoolVector &boolVector);
+  HRESULT WriteHashDigests(
+      const CRecordVector<bool> &digestsDefined,
+      const CRecordVector<UInt32> &hashDigests);
+
+  HRESULT WritePackInfo(
+      UInt64 dataOffset,
+      const CRecordVector<UInt64> &packSizes,
+      const CRecordVector<bool> &packCRCsDefined,
+      const CRecordVector<UInt32> &packCRCs);
+
+  HRESULT WriteUnPackInfo(const CObjectVector<CFolder> &folders);
+
+  HRESULT WriteSubStreamsInfo(
+      const CObjectVector<CFolder> &folders,
+      const CRecordVector<CNum> &numUnPackStreamsInFolders,
+      const CRecordVector<UInt64> &unPackSizes,
+      const CRecordVector<bool> &digestsDefined,
+      const CRecordVector<UInt32> &hashDigests);
+
+  /*
+  HRESULT WriteStreamsInfo(
+      UInt64 dataOffset,
+      const CRecordVector<UInt64> &packSizes,
+      const CRecordVector<bool> &packCRCsDefined,
+      const CRecordVector<UInt32> &packCRCs,
+      bool externalFolders,
+      UInt64 externalFoldersStreamIndex,
+      const CObjectVector<CFolder> &folders,
+      const CRecordVector<CNum> &numUnPackStreamsInFolders,
+      const CRecordVector<UInt64> &unPackSizes,
+      const CRecordVector<bool> &digestsDefined,
+      const CRecordVector<UInt32> &hashDigests);
+  */
+
+
+  HRESULT WriteTime(const CObjectVector<CFileItem> &files, Byte type);
+
+  HRESULT EncodeStream(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      CEncoder &encoder, const Byte *data, size_t dataSize,
+      CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders);
+  HRESULT EncodeStream(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      CEncoder &encoder, const CByteBuffer &data, 
+      CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders);
+  HRESULT WriteHeader(
+      const CArchiveDatabase &database,
+      const CHeaderOptions &headerOptions,
+      UInt64 &headerOffset);
+  
+  bool _mainMode;
+
+  bool _dynamicMode;
+
+  bool _countMode;
+  size_t _countSize;
+  COutBuffer _outByte;
+  CWriteBufferLoc _outByte2;
+  CWriteDynamicBuffer _dynamicBuffer;
+  UInt32 _crc;
+
+  #ifdef _7Z_VOL
+  bool _endMarker;
+  #endif
+
+  HRESULT WriteSignature();
+  #ifdef _7Z_VOL
+  HRESULT WriteFinishSignature();
+  #endif
+  HRESULT WriteStartHeader(const CStartHeader &h);
+  #ifdef _7Z_VOL
+  HRESULT WriteFinishHeader(const CFinishHeader &h);
+  #endif
+  CMyComPtr<IOutStream> Stream;
+public:
+
+  COutArchive() { _outByte.Create(1 << 16); }
+  CMyComPtr<ISequentialOutStream> SeqStream;
+  HRESULT Create(ISequentialOutStream *stream, bool endMarker);
+  void Close();
+  HRESULT SkeepPrefixArchiveHeader();
+  HRESULT WriteDatabase(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      const CArchiveDatabase &database,
+      const CCompressionMethodMode *options, 
+      const CHeaderOptions &headerOptions);
+
+  #ifdef _7Z_VOL
+  static UInt32 GetVolHeadersSize(UInt64 dataSize, int nameLength = 0, bool props = false);
+  static UInt64 GetVolPureSize(UInt64 volSize, int nameLength = 0, bool props = false);
+  #endif
+
+};
+
+}}
+
+#endif

+ 162 - 0
lzma/CPP/7zip/Archive/7z/7zProperties.cpp

@@ -0,0 +1,162 @@
+// 7zProperties.cpp
+
+#include "StdAfx.h"
+
+#include "7zProperties.h"
+#include "7zHeader.h"
+#include "7zHandler.h"
+
+// #define _MULTI_PACK
+
+namespace NArchive {
+namespace N7z {
+
+struct CPropMap
+{
+  UInt64 FilePropID;
+  STATPROPSTG StatPROPSTG;
+};
+
+CPropMap kPropMap[] = 
+{
+  { NID::kName, NULL, kpidPath, VT_BSTR},
+  { NID::kSize, NULL, kpidSize, VT_UI8},
+  { NID::kPackInfo, NULL, kpidPackedSize, VT_UI8},
+  
+  #ifdef _MULTI_PACK
+  { 100, L"Pack0", kpidPackedSize0, VT_UI8},
+  { 101, L"Pack1", kpidPackedSize1, VT_UI8},
+  { 102, L"Pack2", kpidPackedSize2, VT_UI8},
+  { 103, L"Pack3", kpidPackedSize3, VT_UI8},
+  { 104, L"Pack4", kpidPackedSize4, VT_UI8},
+  #endif
+
+  { NID::kCreationTime, NULL, kpidCreationTime, VT_FILETIME},
+  { NID::kLastWriteTime, NULL, kpidLastWriteTime, VT_FILETIME},
+  { NID::kLastAccessTime, NULL, kpidLastAccessTime, VT_FILETIME},
+  { NID::kWinAttributes, NULL, kpidAttributes, VT_UI4},
+  { NID::kStartPos, NULL, kpidPosition, VT_UI4},
+
+  { NID::kCRC, NULL, kpidCRC, VT_UI4},
+  
+  { NID::kAnti, NULL, kpidIsAnti, VT_BOOL},
+  // { 97, NULL, kpidSolid, VT_BOOL},
+  #ifndef _SFX
+  { 98, NULL, kpidMethod, VT_BSTR},
+  { 99, NULL, kpidBlock, VT_UI4}
+  #endif
+};
+
+static const int kPropMapSize = sizeof(kPropMap) / sizeof(kPropMap[0]);
+
+static int FindPropInMap(UInt64 filePropID)
+{
+  for (int i = 0; i < kPropMapSize; i++)
+    if (kPropMap[i].FilePropID == filePropID)
+      return i;
+  return -1;
+}
+
+static void CopyOneItem(CRecordVector<UInt64> &src, 
+    CRecordVector<UInt64> &dest, UInt32 item)
+{
+  for (int i = 0; i < src.Size(); i++)
+    if (src[i] == item)
+    {
+      dest.Add(item);
+      src.Delete(i);
+      return;
+    }
+}
+
+static void RemoveOneItem(CRecordVector<UInt64> &src, UInt32 item)
+{
+  for (int i = 0; i < src.Size(); i++)
+    if (src[i] == item)
+    {
+      src.Delete(i);
+      return;
+    }
+}
+
+static void InsertToHead(CRecordVector<UInt64> &dest, UInt32 item)
+{
+  for (int i = 0; i < dest.Size(); i++)
+    if (dest[i] == item)
+    {
+      dest.Delete(i);
+      break;
+    }
+  dest.Insert(0, item);
+}
+
+void CHandler::FillPopIDs()
+{ 
+  _fileInfoPopIDs.Clear();
+
+  #ifdef _7Z_VOL
+  if(_volumes.Size() < 1)
+    return;
+  const CVolume &volume = _volumes.Front();
+  const CArchiveDatabaseEx &_database = volume.Database;
+  #endif
+
+  CRecordVector<UInt64> fileInfoPopIDs = _database.ArchiveInfo.FileInfoPopIDs;
+
+  RemoveOneItem(fileInfoPopIDs, NID::kEmptyStream);
+  RemoveOneItem(fileInfoPopIDs, NID::kEmptyFile);
+
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kName);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kAnti);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kSize);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kPackInfo);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kCreationTime);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kLastWriteTime);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kLastAccessTime);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kWinAttributes);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kCRC);
+  CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kComment);
+  _fileInfoPopIDs += fileInfoPopIDs; 
+ 
+  #ifndef _SFX
+  _fileInfoPopIDs.Add(98);
+  _fileInfoPopIDs.Add(99);
+  #endif
+  #ifdef _MULTI_PACK
+  _fileInfoPopIDs.Add(100);
+  _fileInfoPopIDs.Add(101);
+  _fileInfoPopIDs.Add(102);
+  _fileInfoPopIDs.Add(103);
+  _fileInfoPopIDs.Add(104);
+  #endif
+
+  #ifndef _SFX
+  InsertToHead(_fileInfoPopIDs, NID::kLastWriteTime);
+  InsertToHead(_fileInfoPopIDs, NID::kPackInfo);
+  InsertToHead(_fileInfoPopIDs, NID::kSize);
+  InsertToHead(_fileInfoPopIDs, NID::kName);
+  #endif
+}
+
+STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties)
+{
+  *numProperties = _fileInfoPopIDs.Size();
+  return S_OK;
+}
+
+STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index,     
+      BSTR *name, PROPID *propID, VARTYPE *varType)
+{
+  if((int)index >= _fileInfoPopIDs.Size())
+    return E_INVALIDARG;
+  int indexInMap = FindPropInMap(_fileInfoPopIDs[index]);
+  if (indexInMap == -1)
+    return E_INVALIDARG;
+  const STATPROPSTG &srcItem = kPropMap[indexInMap].StatPROPSTG;
+  *propID = srcItem.propid;
+  *varType = srcItem.vt;
+  *name = 0;
+  return S_OK;
+}
+
+}}

+ 22 - 0
lzma/CPP/7zip/Archive/7z/7zProperties.h

@@ -0,0 +1,22 @@
+// 7zProperties.h
+
+#ifndef __7Z_PROPERTIES_H
+#define __7Z_PROPERTIES_H
+
+#include "../../PropID.h"
+
+namespace NArchive {
+namespace N7z {
+
+enum
+{
+  kpidPackedSize0 = kpidUserDefined,
+  kpidPackedSize1, 
+  kpidPackedSize2,
+  kpidPackedSize3,
+  kpidPackedSize4
+};
+
+}}
+
+#endif

+ 18 - 0
lzma/CPP/7zip/Archive/7z/7zRegister.cpp

@@ -0,0 +1,18 @@
+// 7zRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "7zHandler.h"
+static IInArchive *CreateArc() { return new NArchive::N7z::CHandler;  }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new NArchive::N7z::CHandler;  }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+  { L"7z", L"7z", 0, 7, {'7' + 1 , 'z', 0xBC, 0xAF, 0x27, 0x1C}, 6, false, CreateArc, CreateArcOut };
+
+REGISTER_ARC_DEC_SIG(7z)

+ 24 - 0
lzma/CPP/7zip/Archive/7z/7zSpecStream.cpp

@@ -0,0 +1,24 @@
+// 7zSpecStream.cpp
+
+#include "StdAfx.h"
+
+#include "7zSpecStream.h"
+
+STDMETHODIMP CSequentialInStreamSizeCount2::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+  UInt32 realProcessedSize;
+  HRESULT result = _stream->Read(data, size, &realProcessedSize);
+  _size += realProcessedSize;
+  if (processedSize != 0)
+    *processedSize = realProcessedSize;
+  return result; 
+}
+
+STDMETHODIMP CSequentialInStreamSizeCount2::GetSubStreamSize(
+    UInt64 subStream, UInt64 *value)
+{
+  if (_getSubStreamSize == NULL)
+    return E_NOTIMPL;
+  return  _getSubStreamSize->GetSubStreamSize(subStream, value);
+}
+

+ 35 - 0
lzma/CPP/7zip/Archive/7z/7zSpecStream.h

@@ -0,0 +1,35 @@
+// 7zSpecStream.h
+
+#ifndef __7Z_SPEC_STREAM_H
+#define __7Z_SPEC_STREAM_H
+
+#include "../../IStream.h"
+#include "../../ICoder.h"
+#include "../../../Common/MyCom.h"
+
+class CSequentialInStreamSizeCount2: 
+  public ISequentialInStream,
+  public ICompressGetSubStreamSize,
+  public CMyUnknownImp
+{
+  CMyComPtr<ISequentialInStream> _stream;
+  CMyComPtr<ICompressGetSubStreamSize> _getSubStreamSize;
+  UInt64 _size;
+public:
+  void Init(ISequentialInStream *stream)
+  {
+    _stream = stream;
+    _getSubStreamSize = 0;
+    _stream.QueryInterface(IID_ICompressGetSubStreamSize, &_getSubStreamSize);
+    _size = 0;
+  }
+  UInt64 GetSize() const { return _size; }
+
+  MY_UNKNOWN_IMP1(ICompressGetSubStreamSize)
+
+  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+
+  STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
+};
+
+#endif

+ 1029 - 0
lzma/CPP/7zip/Archive/7z/7zUpdate.cpp

@@ -0,0 +1,1029 @@
+// UpdateMain.cpp
+
+#include "StdAfx.h"
+
+#include "7zUpdate.h"
+#include "7zFolderInStream.h"
+#include "7zEncode.h"
+#include "7zHandler.h"
+#include "7zOut.h"
+
+#include "../../Compress/Copy/CopyCoder.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/LimitedStreams.h"
+#include "../Common/ItemNameUtils.h"
+
+namespace NArchive {
+namespace N7z {
+
+static const wchar_t *kMatchFinderForBCJ2_LZMA = L"BT2";
+static const UInt32 kDictionaryForBCJ2_LZMA = 1 << 20;
+static const UInt32 kAlgorithmForBCJ2_LZMA = 1;
+static const UInt32 kNumFastBytesForBCJ2_LZMA = 64;
+
+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);
+}
+
+static int GetReverseSlashPos(const UString &name)
+{
+  int slashPos = name.ReverseFind(L'/');
+  #ifdef _WIN32
+  int slash1Pos = name.ReverseFind(L'\\');
+  slashPos = MyMax(slashPos, slash1Pos);
+  #endif
+  return slashPos;
+}
+
+int CUpdateItem::GetExtensionPos() const
+{
+  int slashPos = GetReverseSlashPos(Name);
+  int dotPos = Name.ReverseFind(L'.');
+  if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0))
+    return Name.Length();
+  return dotPos + 1;
+}
+
+UString CUpdateItem::GetExtension() const
+{
+  return Name.Mid(GetExtensionPos());
+}
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+static int CompareBuffers(const CByteBuffer &a1, const CByteBuffer &a2)
+{
+  size_t c1 = a1.GetCapacity();
+  size_t c2 = a2.GetCapacity();
+  RINOZ(MyCompare(c1, c2));
+  for (size_t i = 0; i < c1; i++)
+    RINOZ(MyCompare(a1[i], a2[i]));
+  return 0;
+}
+
+static int CompareCoders(const CCoderInfo &c1, const CCoderInfo &c2)
+{
+  RINOZ(MyCompare(c1.NumInStreams, c2.NumInStreams));
+  RINOZ(MyCompare(c1.NumOutStreams, c2.NumOutStreams));
+  RINOZ(MyCompare(c1.MethodID, c2.MethodID));
+  return CompareBuffers(c1.Properties, c2.Properties);
+}
+
+static int CompareBindPairs(const CBindPair &b1, const CBindPair &b2)
+{
+  RINOZ(MyCompare(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(MyCompare(s1, s2));
+  int i;
+  for (i = 0; i < s1; i++)
+    RINOZ(CompareCoders(f1.Coders[i], f2.Coders[i]));
+  s1 = f1.BindPairs.Size();
+  s2 = f2.BindPairs.Size();
+  RINOZ(MyCompare(s1, s2));
+  for (i = 0; i < s1; i++)
+    RINOZ(CompareBindPairs(f1.BindPairs[i], f2.BindPairs[i]));
+  return 0;
+}
+
+static int CompareFiles(const CFileItem &f1, const CFileItem &f2)
+{
+  return MyStringCompareNoCase(f1.Name, f2.Name);
+}
+
+static int CompareFolderRefs(const int *p1, const int *p2, void *param)
+{
+  int i1 = *p1;
+  int i2 = *p2;
+  const CArchiveDatabaseEx &db = *(const CArchiveDatabaseEx *)param;
+  RINOZ(CompareFolders(
+      db.Folders[i1],
+      db.Folders[i2]));
+  RINOZ(MyCompare(
+      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]]);
+}
+
+////////////////////////////////////////////////////////////
+
+static int CompareEmptyItems(const int *p1, const int *p2, void *param)
+{
+  const CObjectVector<CUpdateItem> &updateItems = *(const CObjectVector<CUpdateItem> *)param;
+  const CUpdateItem &u1 = updateItems[*p1];
+  const CUpdateItem &u2 = updateItems[*p2];
+  if (u1.IsDirectory != u2.IsDirectory)
+    return (u1.IsDirectory) ? 1 : -1;
+  if (u1.IsDirectory)
+  {
+    if (u1.IsAnti != u2.IsAnti)
+      return (u1.IsAnti ? 1 : -1);
+    int n = MyStringCompareNoCase(u1.Name, u2.Name);
+    return -n;
+  }
+  if (u1.IsAnti != u2.IsAnti)
+    return (u1.IsAnti ? 1 : -1);
+  return MyStringCompareNoCase(u1.Name, u2.Name);
+}
+
+static const char *g_Exts = 
+  " lzma 7z ace arc arj bz bz2 deb lzo lzx gz pak rpm sit tgz tbz tbz2 tgz cab ha lha lzh rar 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 rc java cs pas bas vb cls ctl frm dlg def" 
+  " f77 f f90 f95"
+  " asm sql manifest dep "
+  " mak clw csproj vcproj sln dsp dsw "
+  " class "
+  " bat cmd"
+  " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml"
+  " awk sed hta js php php3 php4 php5 phptml pl pm py pyo rb sh tcl 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";
+
+int GetExtIndex(const char *ext)
+{
+  int extIndex = 1;
+  const char *p = g_Exts;
+  for (;;)
+  {
+    char c = *p++;
+    if (c == 0)
+      return extIndex;
+    if (c == ' ')
+      continue;
+    int 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
+{
+  UInt32 Index;
+  const CUpdateItem *UpdateItem;
+  UInt32 ExtensionPos;
+  UInt32 NamePos;
+  int ExtensionIndex;
+  CRefItem(UInt32 index, const CUpdateItem &updateItem, bool sortByType):
+    Index(index),
+    UpdateItem(&updateItem),
+    ExtensionPos(0),
+    NamePos(0),
+    ExtensionIndex(0)
+  {
+    if (sortByType)
+    {
+      int slashPos = GetReverseSlashPos(updateItem.Name);
+      NamePos = ((slashPos >= 0) ? (slashPos + 1) : 0);
+      int dotPos = updateItem.Name.ReverseFind(L'.');
+      if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0))
+        ExtensionPos = updateItem.Name.Length();
+      else 
+      {
+        ExtensionPos = dotPos + 1;
+        UString us = updateItem.Name.Mid(ExtensionPos);
+        if (!us.IsEmpty())
+        {
+          us.MakeLower();
+          int i;
+          AString s;
+          for (i = 0; i < us.Length(); i++)
+          {
+            wchar_t c = us[i];
+            if (c >= 0x80)
+              break;
+            s += (char)c;
+          }
+          if (i == us.Length())
+            ExtensionIndex = GetExtIndex(s);
+          else
+            ExtensionIndex = 0;
+        }
+      }
+    }
+  }
+};
+
+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;
+  int n;
+  if (u1.IsDirectory != u2.IsDirectory)
+    return (u1.IsDirectory) ? 1 : -1;
+  if (u1.IsDirectory)
+  {
+    if (u1.IsAnti != u2.IsAnti)
+      return (u1.IsAnti ? 1 : -1);
+    n = MyStringCompareNoCase(u1.Name, u2.Name);
+    return -n;
+  }
+  bool sortByType = *(bool *)param;
+  if (sortByType)
+  {
+    RINOZ(MyCompare(a1.ExtensionIndex, a2.ExtensionIndex))
+    RINOZ(MyStringCompareNoCase(u1.Name + a1.ExtensionPos, u2.Name + a2.ExtensionPos));
+    RINOZ(MyStringCompareNoCase(u1.Name + a1.NamePos, u2.Name + a2.NamePos));
+    if (u1.IsLastWriteTimeDefined && u2.IsLastWriteTimeDefined)
+      RINOZ(CompareFileTime(&u1.LastWriteTime, &u2.LastWriteTime));
+    RINOZ(MyCompare(u1.Size, u2.Size))
+  }
+  return MyStringCompareNoCase(u1.Name, u2.Name);
+}
+
+struct CSolidGroup
+{
+  CCompressionMethodMode Method;
+  CRecordVector<UInt32> Indices;
+};
+
+static wchar_t *g_ExeExts[] =
+{
+  L"dll",
+  L"exe",
+  L"ocx",
+  L"sfx",
+  L"sys"
+};
+
+static bool IsExeFile(const UString &ext)
+{
+  for (int i = 0; i < sizeof(g_ExeExts) / sizeof(g_ExeExts[0]); i++)
+    if (ext.CompareNoCase(g_ExeExts[i]) == 0)
+      return true;
+  return false;
+}
+
+static const UInt64 k_LZMA  = 0x030101;
+static const UInt64 k_BCJ   = 0x03030103;
+static const UInt64 k_BCJ2  = 0x0303011B;
+
+static bool GetMethodFull(UInt64 methodID, 
+    UInt32 numInStreams, CMethodFull &methodResult)
+{
+  methodResult.Id = methodID;
+  methodResult.NumInStreams = numInStreams;
+  methodResult.NumOutStreams = 1;
+  return true;
+}
+
+static bool MakeExeMethod(const CCompressionMethodMode &method, 
+    bool bcj2Filter, CCompressionMethodMode &exeMethod)
+{
+  exeMethod = method;
+  if (bcj2Filter)
+  {
+    CMethodFull methodFull;
+    if (!GetMethodFull(k_BCJ2, 4, methodFull))
+      return false;
+    exeMethod.Methods.Insert(0, methodFull);
+    if (!GetMethodFull(k_LZMA, 1, methodFull))
+      return false;
+    {
+      CProp property;
+      property.Id = NCoderPropID::kAlgorithm;
+      property.Value = kAlgorithmForBCJ2_LZMA;
+      methodFull.Properties.Add(property);
+    }
+    {
+      CProp property;
+      property.Id = NCoderPropID::kMatchFinder;
+      property.Value = kMatchFinderForBCJ2_LZMA;
+      methodFull.Properties.Add(property);
+    }
+    {
+      CProp property;
+      property.Id = NCoderPropID::kDictionarySize;
+      property.Value = kDictionaryForBCJ2_LZMA;
+      methodFull.Properties.Add(property);
+    }
+    {
+      CProp property;
+      property.Id = NCoderPropID::kNumFastBytes;
+      property.Value = kNumFastBytesForBCJ2_LZMA;
+      methodFull.Properties.Add(property);
+    }
+
+    exeMethod.Methods.Add(methodFull);
+    exeMethod.Methods.Add(methodFull);
+    CBind bind;
+
+    bind.OutCoder = 0;
+    bind.InStream = 0;
+
+    bind.InCoder = 1;
+    bind.OutStream = 0;
+    exeMethod.Binds.Add(bind);
+
+    bind.InCoder = 2;
+    bind.OutStream = 1;
+    exeMethod.Binds.Add(bind);
+
+    bind.InCoder = 3;
+    bind.OutStream = 2;
+    exeMethod.Binds.Add(bind);
+  }
+  else
+  {
+    CMethodFull methodFull;
+    if (!GetMethodFull(k_BCJ, 1, methodFull))
+      return false;
+    exeMethod.Methods.Insert(0, methodFull);
+    CBind bind;
+    bind.OutCoder = 0;
+    bind.InStream = 0;
+    bind.InCoder = 1;
+    bind.OutStream = 0;
+    exeMethod.Binds.Add(bind);
+  }
+  return true;
+}   
+
+static void SplitFilesToGroups(
+    const CCompressionMethodMode &method, 
+    bool useFilters, bool maxFilter,
+    const CObjectVector<CUpdateItem> &updateItems,
+    CObjectVector<CSolidGroup> &groups)
+{
+  if (method.Methods.Size() != 1 || method.Binds.Size() != 0)
+    useFilters = false;
+  groups.Clear();
+  groups.Add(CSolidGroup());
+  groups.Add(CSolidGroup());
+  CSolidGroup &generalGroup = groups[0];
+  CSolidGroup &exeGroup = groups[1];
+  generalGroup.Method = method;
+  int i;
+  for (i = 0; i < updateItems.Size(); i++)
+  {
+    const CUpdateItem &updateItem = updateItems[i];
+    if (!updateItem.NewData)
+      continue;
+    if (!updateItem.HasStream())
+      continue;
+    if (useFilters)
+    {
+      const UString name = updateItem.Name;
+      int dotPos = name.ReverseFind(L'.');
+      if (dotPos >= 0)
+      {
+        UString ext = name.Mid(dotPos + 1);
+        if (IsExeFile(ext))
+        {
+          exeGroup.Indices.Add(i);
+          continue;
+        }
+      }
+    }
+    generalGroup.Indices.Add(i);
+  }
+  if (exeGroup.Indices.Size() > 0)
+    if (!MakeExeMethod(method, maxFilter, exeGroup.Method))
+      exeGroup.Method = method;
+  for (i = 0; i < groups.Size();)
+    if (groups[i].Indices.Size() == 0)
+      groups.Delete(i);
+    else
+      i++;
+}
+
+static void FromUpdateItemToFileItem(const CUpdateItem &updateItem, 
+    CFileItem &file)
+{
+  file.Name = NItemName::MakeLegalName(updateItem.Name);
+  if (updateItem.AttributesAreDefined)
+    file.SetAttributes(updateItem.Attributes);
+  
+  if (updateItem.IsCreationTimeDefined)
+    file.SetCreationTime(updateItem.CreationTime);
+  if (updateItem.IsLastWriteTimeDefined)
+    file.SetLastWriteTime(updateItem.LastWriteTime);
+  if (updateItem.IsLastAccessTimeDefined)
+    file.SetLastAccessTime(updateItem.LastAccessTime);
+  
+  file.UnPackSize = updateItem.Size;
+  file.IsDirectory = updateItem.IsDirectory;
+  file.IsAnti = updateItem.IsAnti;
+  file.HasStream = updateItem.HasStream();
+}
+
+static HRESULT Update2(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    IInStream *inStream,
+    const CArchiveDatabaseEx *database,
+    const CObjectVector<CUpdateItem> &updateItems,
+    ISequentialOutStream *seqOutStream,
+    IArchiveUpdateCallback *updateCallback,
+    const CUpdateOptions &options)
+{
+  UInt64 numSolidFiles = options.NumSolidFiles;
+  if (numSolidFiles == 0)
+    numSolidFiles = 1;
+  /*
+  CMyComPtr<IOutStream> outStream;
+  RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream));
+  if (!outStream)
+    return E_NOTIMPL;
+  */
+
+  UInt64 startBlockSize = database != 0 ? database->ArchiveInfo.StartPosition: 0;
+  if (startBlockSize > 0 && !options.RemoveSfxBlock)
+  {
+    RINOK(WriteRange(inStream, seqOutStream, 0, startBlockSize, NULL));
+  }
+
+  CRecordVector<int> fileIndexToUpdateIndexMap;
+  if (database != 0)
+  {
+    fileIndexToUpdateIndexMap.Reserve(database->Files.Size());
+    for (int i = 0; i < database->Files.Size(); i++)
+      fileIndexToUpdateIndexMap.Add(-1);
+  }
+  int i;
+  for(i = 0; i < updateItems.Size(); i++)
+  {
+    int index = updateItems[i].IndexInArchive;
+    if (index != -1)
+      fileIndexToUpdateIndexMap[index] = i;
+  }
+
+  CRecordVector<int> folderRefs;
+  if (database != 0)
+  {
+    for(i = 0; i < database->Folders.Size(); i++)
+    {
+      CNum indexInFolder = 0;
+      CNum numCopyItems = 0;
+      CNum numUnPackStreams = database->NumUnPackStreamsVector[i];
+      for (CNum fileIndex = database->FolderStartFileIndex[i];
+      indexInFolder < numUnPackStreams; fileIndex++)
+      {
+        if (database->Files[fileIndex].HasStream)
+        {
+          indexInFolder++;
+          int updateIndex = fileIndexToUpdateIndexMap[fileIndex];
+          if (updateIndex >= 0)
+            if (!updateItems[updateIndex].NewData)
+              numCopyItems++;
+        }
+      }
+      if (numCopyItems != numUnPackStreams && numCopyItems != 0)
+        return E_NOTIMPL; // It needs repacking !!!
+      if (numCopyItems > 0)
+        folderRefs.Add(i);
+    }
+    folderRefs.Sort(CompareFolderRefs, (void *)database);
+  }
+
+  CArchiveDatabase newDatabase;
+
+  ////////////////////////////
+
+  COutArchive archive;
+  RINOK(archive.Create(seqOutStream, false));
+  RINOK(archive.SkeepPrefixArchiveHeader());
+  UInt64 complexity = 0;
+  for(i = 0; i < folderRefs.Size(); i++)
+    complexity += database->GetFolderFullPackSize(folderRefs[i]);
+  UInt64 inSizeForReduce = 0;
+  for(i = 0; i < updateItems.Size(); i++)
+  {
+    const CUpdateItem &updateItem = updateItems[i];
+    if (updateItem.NewData)
+    {
+      complexity += updateItem.Size;
+      if (numSolidFiles == 1)
+      {
+        if (updateItem.Size > inSizeForReduce)
+          inSizeForReduce = updateItem.Size;
+      }
+      else
+        inSizeForReduce += updateItem.Size;
+    }
+  }
+  RINOK(updateCallback->SetTotal(complexity));
+  complexity = 0;
+  RINOK(updateCallback->SetCompleted(&complexity));
+
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(updateCallback, true);
+
+  /////////////////////////////////////////
+  // Write Copy Items
+
+  for(i = 0; i < folderRefs.Size(); i++)
+  {
+    int folderIndex = folderRefs[i];
+    
+    lps->ProgressOffset = complexity;
+    UInt64 packSize = database->GetFolderFullPackSize(folderIndex);
+    RINOK(WriteRange(inStream, archive.SeqStream,
+        database->GetFolderStreamPos(folderIndex, 0), packSize, progress));
+    complexity += packSize;
+    
+    const CFolder &folder = database->Folders[folderIndex];
+    CNum startIndex = database->FolderStartPackStreamIndex[folderIndex];
+    for (int j = 0; j < folder.PackStreams.Size(); j++)
+    {
+      newDatabase.PackSizes.Add(database->PackSizes[startIndex + j]);
+      // newDatabase.PackCRCsDefined.Add(database.PackCRCsDefined[startIndex + j]);
+      // newDatabase.PackCRCs.Add(database.PackCRCs[startIndex + j]);
+    }
+    newDatabase.Folders.Add(folder);
+
+    CNum numUnPackStreams = database->NumUnPackStreamsVector[folderIndex];
+    newDatabase.NumUnPackStreamsVector.Add(numUnPackStreams);
+
+    CNum indexInFolder = 0;
+    for (CNum fi = database->FolderStartFileIndex[folderIndex];
+        indexInFolder < numUnPackStreams; fi++)
+    {
+      CFileItem file = database->Files[fi];
+      if (file.HasStream)
+      {
+        indexInFolder++;
+        int updateIndex = fileIndexToUpdateIndexMap[fi];
+        if (updateIndex >= 0)
+        {
+          const CUpdateItem &updateItem = updateItems[updateIndex];
+          if (updateItem.NewProperties)
+          {
+            CFileItem file2;
+            FromUpdateItemToFileItem(updateItem, file2);
+            file2.UnPackSize = file.UnPackSize;
+            file2.FileCRC = file.FileCRC;
+            file2.IsFileCRCDefined = file.IsFileCRCDefined;
+            file2.HasStream = file.HasStream;
+            file = file2;
+          }
+        }
+        newDatabase.Files.Add(file);
+      }
+    }
+  }
+
+  /////////////////////////////////////////
+  // Compress New Files
+
+  CObjectVector<CSolidGroup> groups;
+  SplitFilesToGroups(*options.Method, options.UseFilters, options.MaxFilter, 
+      updateItems, groups);
+
+  const UInt32 kMinReduceSize = (1 << 16);
+  if (inSizeForReduce < kMinReduceSize)
+    inSizeForReduce = kMinReduceSize;
+
+  for (int groupIndex = 0; groupIndex < groups.Size(); groupIndex++)
+  {
+    const CSolidGroup &group = groups[groupIndex];
+    int numFiles = group.Indices.Size();
+    if (numFiles == 0)
+      continue;
+    CRecordVector<CRefItem> refItems;
+    refItems.Reserve(numFiles);
+    bool sortByType = (numSolidFiles > 1);
+    for (i = 0; i < numFiles; i++)
+      refItems.Add(CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType));
+    refItems.Sort(CompareUpdateItems, (void *)&sortByType);
+    
+    CRecordVector<UInt32> indices;
+    indices.Reserve(numFiles);
+
+    for (i = 0; i < numFiles; i++)
+    {
+      UInt32 index = refItems[i].Index;
+      indices.Add(index);
+      /*
+      const CUpdateItem &updateItem = updateItems[index];
+      CFileItem file;
+      if (updateItem.NewProperties)
+        FromUpdateItemToFileItem(updateItem, file);
+      else
+        file = database.Files[updateItem.IndexInArchive];
+      if (file.IsAnti || file.IsDirectory)
+        return E_FAIL;
+      newDatabase.Files.Add(file);
+      */
+    }
+    
+    CEncoder encoder(group.Method);
+
+    for (i = 0; i < numFiles;)
+    {
+      UInt64 totalSize = 0;
+      int numSubFiles;
+      UString prevExtension;
+      for (numSubFiles = 0; i + numSubFiles < numFiles && 
+          numSubFiles < numSolidFiles; numSubFiles++)
+      {
+        const CUpdateItem &updateItem = updateItems[indices[i + numSubFiles]];
+        totalSize += updateItem.Size;
+        if (totalSize > options.NumSolidBytes)
+          break;
+        if (options.SolidExtension)
+        {
+          UString ext = updateItem.GetExtension();
+          if (numSubFiles == 0)
+            prevExtension = ext;
+          else
+            if (ext.CompareNoCase(prevExtension) != 0)
+              break;
+        }
+      }
+      if (numSubFiles < 1)
+        numSubFiles = 1;
+
+      CFolderInStream *inStreamSpec = new CFolderInStream;
+      CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec);
+      inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);
+      
+      CFolder folderItem;
+
+      int startPackIndex = newDatabase.PackSizes.Size();
+      RINOK(encoder.Encode(
+          EXTERNAL_CODECS_LOC_VARS
+          solidInStream, NULL, &inSizeForReduce, folderItem, 
+          archive.SeqStream, newDatabase.PackSizes, progress));
+
+      for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
+        lps->OutSize += newDatabase.PackSizes[startPackIndex];
+
+      lps->InSize += folderItem.GetUnPackSize();
+      // for()
+      // newDatabase.PackCRCsDefined.Add(false);
+      // newDatabase.PackCRCs.Add(0);
+      
+      newDatabase.Folders.Add(folderItem);
+      
+      CNum numUnPackStreams = 0;
+      for (int subIndex = 0; subIndex < numSubFiles; subIndex++)
+      {
+        const CUpdateItem &updateItem = updateItems[indices[i + subIndex]];
+        CFileItem file;
+        if (updateItem.NewProperties)
+          FromUpdateItemToFileItem(updateItem, file);
+        else
+          file = database->Files[updateItem.IndexInArchive];
+        if (file.IsAnti || file.IsDirectory)
+          return E_FAIL;
+        
+        /*
+        CFileItem &file = newDatabase.Files[
+              startFileIndexInDatabase + i + subIndex];
+        */
+        if (!inStreamSpec->Processed[subIndex])
+        {
+          continue;
+          // file.Name += L".locked";
+        }
+
+        file.FileCRC = inStreamSpec->CRCs[subIndex];
+        file.UnPackSize = inStreamSpec->Sizes[subIndex];
+        if (file.UnPackSize != 0)
+        {
+          file.IsFileCRCDefined = true;
+          file.HasStream = true;
+          numUnPackStreams++;
+        }
+        else
+        {
+          file.IsFileCRCDefined = false;
+          file.HasStream = false;
+        }
+        newDatabase.Files.Add(file);
+      }
+      // numUnPackStreams = 0 is very bad case for locked files
+      // v3.13 doesn't understand it.
+      newDatabase.NumUnPackStreamsVector.Add(numUnPackStreams);
+      i += numSubFiles;
+    }
+  }
+
+  {
+    /////////////////////////////////////////
+    // Write Empty Files & Folders
+    
+    CRecordVector<int> emptyRefs;
+    for(i = 0; i < updateItems.Size(); i++)
+    {
+      const CUpdateItem &updateItem = updateItems[i];
+      if (updateItem.NewData)
+      {
+        if (updateItem.HasStream())
+          continue;
+      }
+      else
+        if (updateItem.IndexInArchive != -1)
+          if (database->Files[updateItem.IndexInArchive].HasStream)
+            continue;
+      emptyRefs.Add(i);
+    }
+    emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems);
+    for(i = 0; i < emptyRefs.Size(); i++)
+    {
+      const CUpdateItem &updateItem = updateItems[emptyRefs[i]];
+      CFileItem file;
+      if (updateItem.NewProperties)
+        FromUpdateItemToFileItem(updateItem, file);
+      else
+        file = database->Files[updateItem.IndexInArchive];
+      newDatabase.Files.Add(file);
+    }
+  }
+    
+  /*
+  if (newDatabase.Files.Size() != updateItems.Size())
+    return E_FAIL;
+  */
+
+  return archive.WriteDatabase(EXTERNAL_CODECS_LOC_VARS
+      newDatabase, options.HeaderMethod, options.HeaderOptions);
+}
+
+#ifdef _7Z_VOL
+
+static const UInt64 k_Copy = 0x0;
+
+static HRESULT WriteVolumeHeader(COutArchive &archive, CFileItem &file, const CUpdateOptions &options)
+{
+  CCoderInfo coder;
+  coder.NumInStreams = coder.NumOutStreams = 1;
+  coder.MethodID = k_Copy;
+  
+  CFolder folder;
+  folder.Coders.Add(coder);
+  folder.PackStreams.Add(0);
+  
+  CNum numUnPackStreams = 0;
+  if (file.UnPackSize != 0)
+  {
+    file.IsFileCRCDefined = true;
+    file.HasStream = true;
+    numUnPackStreams++;
+  }
+  else
+  {
+    throw 1;
+    file.IsFileCRCDefined = false;
+    file.HasStream = false;
+  }
+  folder.UnPackSizes.Add(file.UnPackSize);
+  
+  CArchiveDatabase newDatabase;
+  newDatabase.Files.Add(file);
+  newDatabase.Folders.Add(folder);
+  newDatabase.NumUnPackStreamsVector.Add(numUnPackStreams);
+  newDatabase.PackSizes.Add(file.UnPackSize);
+  newDatabase.PackCRCsDefined.Add(false);
+  newDatabase.PackCRCs.Add(file.FileCRC);
+  
+  return archive.WriteDatabase(newDatabase, 
+      options.HeaderMethod, 
+      false, 
+      false);
+}
+
+HRESULT UpdateVolume(
+    IInStream *inStream,
+    const CArchiveDatabaseEx *database,
+    CObjectVector<CUpdateItem> &updateItems,
+    ISequentialOutStream *seqOutStream,
+    IArchiveUpdateCallback *updateCallback,
+    const CUpdateOptions &options)
+{
+  if (updateItems.Size() != 1)
+    return E_NOTIMPL;
+
+  CMyComPtr<IArchiveUpdateCallback2> volumeCallback;
+  RINOK(updateCallback->QueryInterface(IID_IArchiveUpdateCallback2, (void **)&volumeCallback));
+  if (!volumeCallback)
+    return E_NOTIMPL;
+
+  CMyComPtr<ISequentialInStream> fileStream;
+  HRESULT result = updateCallback->GetStream(0, &fileStream);
+  if (result != S_OK && result != S_FALSE)
+    return result;
+  if (result == S_FALSE)
+    return E_FAIL;
+  
+  CFileItem file;
+  
+  const CUpdateItem &updateItem = updateItems[0];
+  if (updateItem.NewProperties)
+    FromUpdateItemToFileItem(updateItem, file);
+  else
+    file = database->Files[updateItem.IndexInArchive];
+  if (file.IsAnti || file.IsDirectory)
+    return E_FAIL;
+
+  UInt64 complexity = 0;
+  file.IsStartPosDefined = true;
+  file.StartPos = 0;
+  for (UInt64 volumeIndex = 0; true; volumeIndex++)
+  { 
+    UInt64 volSize;
+    RINOK(volumeCallback->GetVolumeSize(volumeIndex, &volSize));
+    UInt64 pureSize = COutArchive::GetVolPureSize(volSize, file.Name.Length(), true);
+    CMyComPtr<ISequentialOutStream> volumeStream;
+    RINOK(volumeCallback->GetVolumeStream(volumeIndex, &volumeStream));
+   
+    COutArchive archive;
+    RINOK(archive.Create(volumeStream, true));
+    RINOK(archive.SkeepPrefixArchiveHeader());
+        
+    CSequentialInStreamWithCRC *inCrcStreamSpec = new CSequentialInStreamWithCRC;
+    CMyComPtr<ISequentialInStream> inCrcStream = inCrcStreamSpec;
+    inCrcStreamSpec->Init(fileStream);
+
+    RINOK(WriteRange(inCrcStream, volumeStream, pureSize, updateCallback, complexity));
+    file.UnPackSize = inCrcStreamSpec->GetSize();
+    if (file.UnPackSize == 0)
+      break;
+    file.FileCRC = inCrcStreamSpec->GetCRC();
+    RINOK(WriteVolumeHeader(archive, file, options));
+    file.StartPos += file.UnPackSize;
+    if (file.UnPackSize < pureSize)
+      break;
+  }
+  return S_OK;
+}
+
+class COutVolumeStream: 
+  public ISequentialOutStream,
+  public CMyUnknownImp
+{
+  int _volIndex;
+  UInt64 _volSize;
+  UInt64 _curPos;
+  CMyComPtr<ISequentialOutStream> _volumeStream;
+  COutArchive _archive;
+  CCRC _crc;
+
+public:
+  MY_UNKNOWN_IMP
+
+  CFileItem _file;
+  CUpdateOptions _options;
+  CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
+  void Init(IArchiveUpdateCallback2 *volumeCallback, 
+      const UString &name)  
+  { 
+    _file.Name = name;
+    _file.IsStartPosDefined = true;
+    _file.StartPos = 0;
+    
+    VolumeCallback = volumeCallback;
+    _volIndex = 0;
+    _volSize = 0;
+  }
+  
+  HRESULT Flush();
+  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+HRESULT COutVolumeStream::Flush()
+{
+  if (_volumeStream)
+  {
+    _file.UnPackSize = _curPos;
+    _file.FileCRC = _crc.GetDigest();
+    RINOK(WriteVolumeHeader(_archive, _file, _options));
+    _archive.Close();
+    _volumeStream.Release();
+    _file.StartPos += _file.UnPackSize;
+  }
+  return S_OK;
+}
+
+STDMETHODIMP COutVolumeStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+  if(processedSize != NULL)
+    *processedSize = 0;
+  while(size > 0)
+  {
+    if (!_volumeStream)
+    {
+      RINOK(VolumeCallback->GetVolumeSize(_volIndex, &_volSize));
+      RINOK(VolumeCallback->GetVolumeStream(_volIndex, &_volumeStream));
+      _volIndex++;
+      _curPos = 0;
+      RINOK(_archive.Create(_volumeStream, true));
+      RINOK(_archive.SkeepPrefixArchiveHeader());
+      _crc.Init();
+      continue;
+    }
+    UInt64 pureSize = COutArchive::GetVolPureSize(_volSize, _file.Name.Length());
+    UInt32 curSize = (UInt32)MyMin(UInt64(size), pureSize - _curPos);
+
+    _crc.Update(data, curSize);
+    UInt32 realProcessed;
+    RINOK(_volumeStream->Write(data, curSize, &realProcessed))
+    data = (void *)((Byte *)data + realProcessed);
+    size -= realProcessed;
+    if(processedSize != NULL)
+      *processedSize += realProcessed;
+    _curPos += realProcessed;
+    if (realProcessed != curSize && realProcessed == 0)
+      return E_FAIL;
+    if (_curPos == pureSize)
+    {
+      RINOK(Flush());
+    }
+  }
+  return S_OK;
+}
+
+#endif
+
+HRESULT Update(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    IInStream *inStream,
+    const CArchiveDatabaseEx *database,
+    const CObjectVector<CUpdateItem> &updateItems,
+    ISequentialOutStream *seqOutStream,
+    IArchiveUpdateCallback *updateCallback,
+    const CUpdateOptions &options)
+{
+  #ifdef _7Z_VOL
+  if (seqOutStream)
+  #endif
+    return Update2(
+        EXTERNAL_CODECS_LOC_VARS
+        inStream, database, updateItems,
+        seqOutStream, updateCallback, options);
+  #ifdef _7Z_VOL
+  if (options.VolumeMode)
+    return UpdateVolume(inStream, database, updateItems,
+      seqOutStream, updateCallback, options);
+  COutVolumeStream *volStreamSpec = new COutVolumeStream;
+  CMyComPtr<ISequentialOutStream> volStream = volStreamSpec;
+  CMyComPtr<IArchiveUpdateCallback2> volumeCallback;
+  RINOK(updateCallback->QueryInterface(IID_IArchiveUpdateCallback2, (void **)&volumeCallback));
+  if (!volumeCallback)
+    return E_NOTIMPL;
+  volStreamSpec->Init(volumeCallback, L"a.7z");
+  volStreamSpec->_options = options;
+  RINOK(Update2(inStream, database, updateItems,
+    volStream, updateCallback, options));
+  return volStreamSpec->Flush();
+  #endif
+}
+
+}}

+ 80 - 0
lzma/CPP/7zip/Archive/7z/7zUpdate.h

@@ -0,0 +1,80 @@
+// 7zUpdate.h
+
+#ifndef __7Z_UPDATE_H
+#define __7Z_UPDATE_H
+
+#include "7zIn.h"
+#include "7zOut.h"
+#include "7zCompressionMode.h"
+
+#include "../IArchive.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CUpdateItem
+{
+  bool NewData;
+  bool NewProperties;
+  int IndexInArchive;
+  int IndexInClient;
+  
+  UInt32 Attributes;
+  FILETIME CreationTime;
+  FILETIME LastWriteTime;
+  FILETIME LastAccessTime;
+
+  UInt64 Size;
+  UString Name;
+  
+  bool IsAnti;
+  bool IsDirectory;
+
+  bool IsCreationTimeDefined;
+  bool IsLastWriteTimeDefined;
+  bool IsLastAccessTimeDefined;
+  bool AttributesAreDefined;
+
+  bool HasStream() const 
+    { return !IsDirectory && !IsAnti && Size != 0; }
+  CUpdateItem():  
+      IsAnti(false), 
+      AttributesAreDefined(false), 
+      IsCreationTimeDefined(false), 
+      IsLastWriteTimeDefined(false), 
+      IsLastAccessTimeDefined(false)
+      {}
+  void SetDirectoryStatusFromAttributes()
+    { IsDirectory = ((Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0); };
+
+  int GetExtensionPos() const;
+  UString GetExtension() const;
+};
+
+struct CUpdateOptions
+{
+  const CCompressionMethodMode *Method;
+  const CCompressionMethodMode *HeaderMethod;
+  bool UseFilters;
+  bool MaxFilter;
+
+  CHeaderOptions HeaderOptions;
+
+  UInt64 NumSolidFiles;
+  UInt64 NumSolidBytes;
+  bool SolidExtension;
+  bool RemoveSfxBlock;
+  bool VolumeMode;
+};
+
+HRESULT Update(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    IInStream *inStream,
+    const CArchiveDatabaseEx *database,
+    const CObjectVector<CUpdateItem> &updateItems,
+    ISequentialOutStream *seqOutStream,
+    IArchiveUpdateCallback *updateCallback,
+    const CUpdateOptions &options);
+}}
+
+#endif

+ 3 - 0
lzma/CPP/7zip/Archive/7z/StdAfx.cpp

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

+ 9 - 0
lzma/CPP/7zip/Archive/7z/StdAfx.h

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

+ 6 - 0
lzma/CPP/7zip/Archive/Archive.def

@@ -0,0 +1,6 @@
+EXPORTS
+  CreateObject PRIVATE
+  GetHandlerProperty PRIVATE
+  GetNumberOfFormats PRIVATE
+  GetHandlerProperty2 PRIVATE
+  CreateObject PRIVATE

+ 9 - 0
lzma/CPP/7zip/Archive/Archive2.def

@@ -0,0 +1,9 @@
+EXPORTS
+  CreateObject PRIVATE
+  GetHandlerProperty PRIVATE
+  GetNumberOfFormats PRIVATE
+  GetHandlerProperty2 PRIVATE
+  CreateObject PRIVATE
+  GetNumberOfMethods PRIVATE
+  GetMethodProperty PRIVATE
+  SetLargePageMode PRIVATE

+ 130 - 0
lzma/CPP/7zip/Archive/ArchiveExports.cpp

@@ -0,0 +1,130 @@
+// ArchiveExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/Types.h"
+#include "../../Windows/PropVariant.h"
+#include "../Common/RegisterArc.h"
+
+#include "IArchive.h"
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+static const unsigned int kNumArcsMax = 32;
+static unsigned int g_NumArcs = 0;
+static const CArcInfo *g_Arcs[kNumArcsMax]; 
+void RegisterArc(const CArcInfo *arcInfo) 
+{ 
+  if (g_NumArcs < kNumArcsMax)
+    g_Arcs[g_NumArcs++] = arcInfo; 
+}
+
+DEFINE_GUID(CLSID_CArchiveHandler, 
+0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
+
+#define CLS_ARC_ID_ITEM(cls) ((cls).Data4[5])
+
+static inline HRESULT SetPropString(const char *s, unsigned int size, PROPVARIANT *value)
+{
+  if ((value->bstrVal = ::SysAllocStringByteLen(s, size)) != 0)
+    value->vt = VT_BSTR;
+  return S_OK;
+}
+
+static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value)
+{
+  return SetPropString((const char *)&guid, sizeof(GUID), value);
+}
+
+int FindFormatCalssId(const GUID *clsID)
+{
+  GUID cls = *clsID;
+  CLS_ARC_ID_ITEM(cls) = 0;
+  if (cls != CLSID_CArchiveHandler)
+    return -1;
+  Byte id = CLS_ARC_ID_ITEM(*clsID);
+  for (UInt32 i = 0; i < g_NumArcs; i++)
+    if (g_Arcs[i]->ClassId == id)
+      return i;
+  return -1;
+}
+
+STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject)
+{
+  COM_TRY_BEGIN
+  {
+    int needIn = (*iid == IID_IInArchive);
+    int needOut = (*iid == IID_IOutArchive);
+    if (!needIn && !needOut)
+      return E_NOINTERFACE;
+    int formatIndex = FindFormatCalssId(clsid);
+    if (formatIndex < 0)
+      return CLASS_E_CLASSNOTAVAILABLE;
+    
+    const CArcInfo &arc = *g_Arcs[formatIndex];
+    if (needIn)
+    {
+      *outObject = arc.CreateInArchive();
+      ((IInArchive *)*outObject)->AddRef();
+    }
+    else
+    {
+      if (!arc.CreateOutArchive)
+        return CLASS_E_CLASSNOTAVAILABLE;
+      *outObject = arc.CreateOutArchive();
+      ((IOutArchive *)*outObject)->AddRef();
+    }
+  }
+  COM_TRY_END
+  return S_OK;
+}
+
+STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value)
+{
+  if (formatIndex >= g_NumArcs)
+    return E_INVALIDARG;
+  const CArcInfo &arc = *g_Arcs[formatIndex];
+  NWindows::NCOM::CPropVariant prop;
+  switch(propID)
+  {
+    case NArchive::kName:
+      prop = arc.Name;
+      break;
+    case NArchive::kClassID:
+    {
+      GUID clsId = CLSID_CArchiveHandler;
+      CLS_ARC_ID_ITEM(clsId) = arc.ClassId;
+      return SetPropGUID(clsId, value);
+    }
+    case NArchive::kExtension:
+      if (arc.Ext != 0)
+        prop = arc.Ext;
+      break;
+    case NArchive::kAddExtension:
+      if (arc.AddExt != 0)
+        prop = arc.AddExt;
+      break;
+    case NArchive::kUpdate:
+      prop = (bool)(arc.CreateOutArchive != 0);
+      break;
+    case NArchive::kKeepName:
+      prop = arc.KeepName;
+      break;
+    case NArchive::kStartSignature:
+      return SetPropString((const char *)arc.Signature, arc.SignatureSize, value);
+  }
+  prop.Detach(value);
+  return S_OK;
+}
+
+STDAPI GetHandlerProperty(PROPID propID, PROPVARIANT *value)
+{
+  return GetHandlerProperty2(0, propID, value);
+}
+
+STDAPI GetNumberOfFormats(UINT32 *numFormats)
+{
+  *numFormats = g_NumArcs;
+  return S_OK;
+}

+ 121 - 0
lzma/CPP/7zip/Archive/Common/CoderMixer2.cpp

@@ -0,0 +1,121 @@
+// CoderMixer2.cpp
+
+#include "StdAfx.h"
+
+#include "CoderMixer2.h"
+
+namespace NCoderMixer {
+
+CBindReverseConverter::CBindReverseConverter(const CBindInfo &srcBindInfo):
+  _srcBindInfo(srcBindInfo)
+{
+  srcBindInfo.GetNumStreams(NumSrcInStreams, _numSrcOutStreams);
+
+  UInt32  j;
+  for (j = 0; j < NumSrcInStreams; j++)
+  {
+    _srcInToDestOutMap.Add(0);
+    DestOutToSrcInMap.Add(0);
+  }
+  for (j = 0; j < _numSrcOutStreams; j++)
+  {
+    _srcOutToDestInMap.Add(0);
+    _destInToSrcOutMap.Add(0);
+  }
+
+  UInt32 destInOffset = 0;
+  UInt32 destOutOffset = 0;
+  UInt32 srcInOffset = NumSrcInStreams;
+  UInt32 srcOutOffset = _numSrcOutStreams;
+
+  for (int i = srcBindInfo.Coders.Size() - 1; i >= 0; i--)
+  {
+    const CCoderStreamsInfo &srcCoderInfo = srcBindInfo.Coders[i];
+
+    srcInOffset -= srcCoderInfo.NumInStreams;
+    srcOutOffset -= srcCoderInfo.NumOutStreams;
+    
+    UInt32 j;
+    for (j = 0; j < srcCoderInfo.NumInStreams; j++, destOutOffset++)
+    {
+      UInt32 index = srcInOffset + j;
+      _srcInToDestOutMap[index] = destOutOffset;
+      DestOutToSrcInMap[destOutOffset] = index;
+    }
+    for (j = 0; j < srcCoderInfo.NumOutStreams; j++, destInOffset++)
+    {
+      UInt32 index = srcOutOffset + j;
+      _srcOutToDestInMap[index] = destInOffset;
+      _destInToSrcOutMap[destInOffset] = index;
+    }
+  }
+}
+
+void CBindReverseConverter::CreateReverseBindInfo(CBindInfo &destBindInfo)
+{
+  destBindInfo.Coders.Clear();
+  destBindInfo.BindPairs.Clear();
+  destBindInfo.InStreams.Clear();
+  destBindInfo.OutStreams.Clear();
+
+  int i;
+  for (i = _srcBindInfo.Coders.Size() - 1; i >= 0; i--)
+  {
+    const CCoderStreamsInfo &srcCoderInfo = _srcBindInfo.Coders[i];
+    CCoderStreamsInfo destCoderInfo;
+    destCoderInfo.NumInStreams = srcCoderInfo.NumOutStreams;
+    destCoderInfo.NumOutStreams = srcCoderInfo.NumInStreams;
+    destBindInfo.Coders.Add(destCoderInfo);
+  }
+  for (i = _srcBindInfo.BindPairs.Size() - 1; i >= 0; i--)
+  {
+    const CBindPair &srcBindPair = _srcBindInfo.BindPairs[i];
+    CBindPair destBindPair;
+    destBindPair.InIndex = _srcOutToDestInMap[srcBindPair.OutIndex];
+    destBindPair.OutIndex = _srcInToDestOutMap[srcBindPair.InIndex];
+    destBindInfo.BindPairs.Add(destBindPair);
+  }
+  for (i = 0; i < _srcBindInfo.InStreams.Size(); i++)
+    destBindInfo.OutStreams.Add(_srcInToDestOutMap[_srcBindInfo.InStreams[i]]);
+  for (i = 0; i < _srcBindInfo.OutStreams.Size(); i++)
+    destBindInfo.InStreams.Add(_srcOutToDestInMap[_srcBindInfo.OutStreams[i]]);
+}
+
+CCoderInfo2::CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams): 
+    NumInStreams(numInStreams),
+    NumOutStreams(numOutStreams)
+{
+  InSizes.Reserve(NumInStreams);
+  InSizePointers.Reserve(NumInStreams);
+  OutSizePointers.Reserve(NumOutStreams);
+  OutSizePointers.Reserve(NumOutStreams);
+}
+
+static void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes, 
+    CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems)
+{
+  sizes.Clear();
+  sizePointers.Clear();
+  for(UInt32 i = 0; i < numItems; i++)
+  {
+    if (srcSizes == 0 || srcSizes[i] == NULL)
+    {
+      sizes.Add(0);
+      sizePointers.Add(NULL);
+    }
+    else
+    {
+      sizes.Add(*srcSizes[i]);
+      sizePointers.Add(&sizes.Back());
+    }
+  }
+}
+
+void CCoderInfo2::SetCoderInfo(const UInt64 **inSizes,
+      const UInt64 **outSizes)
+{
+  SetSizes(inSizes, InSizes, InSizePointers, NumInStreams);
+  SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams);
+}
+
+}  

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff