Procházet zdrojové kódy

Add 7zMain.c ('Test application for 7z Decoder') and the extra SDK files it needs.

Martijn Laan před 11 měsíci
rodič
revize
873a8819e8

+ 204 - 0
Components/Lzma2/7z.h

@@ -0,0 +1,204 @@
+/* 7z.h -- 7z interface
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_7Z_H
+#define ZIP7_INC_7Z_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define k7zStartHeaderSize 0x20
+#define k7zSignatureSize 6
+
+extern const Byte k7zSignature[k7zSignatureSize];
+
+typedef struct
+{
+  const Byte *Data;
+  size_t Size;
+} CSzData;
+
+/* CSzCoderInfo & CSzFolder support only default methods */
+
+typedef struct
+{
+  size_t PropsOffset;
+  UInt32 MethodID;
+  Byte NumStreams;
+  Byte PropsSize;
+} CSzCoderInfo;
+
+typedef struct
+{
+  UInt32 InIndex;
+  UInt32 OutIndex;
+} CSzBond;
+
+#define SZ_NUM_CODERS_IN_FOLDER_MAX 4
+#define SZ_NUM_BONDS_IN_FOLDER_MAX 3
+#define SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX 4
+
+typedef struct
+{
+  UInt32 NumCoders;
+  UInt32 NumBonds;
+  UInt32 NumPackStreams;
+  UInt32 UnpackStream;
+  UInt32 PackStreams[SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX];
+  CSzBond Bonds[SZ_NUM_BONDS_IN_FOLDER_MAX];
+  CSzCoderInfo Coders[SZ_NUM_CODERS_IN_FOLDER_MAX];
+} CSzFolder;
+
+
+SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd);
+
+typedef struct
+{
+  UInt32 Low;
+  UInt32 High;
+} CNtfsFileTime;
+
+typedef struct
+{
+  Byte *Defs; /* MSB 0 bit numbering */
+  UInt32 *Vals;
+} CSzBitUi32s;
+
+typedef struct
+{
+  Byte *Defs; /* MSB 0 bit numbering */
+  // UInt64 *Vals;
+  CNtfsFileTime *Vals;
+} CSzBitUi64s;
+
+#define SzBitArray_Check(p, i) (((p)[(i) >> 3] & (0x80 >> ((i) & 7))) != 0)
+
+#define SzBitWithVals_Check(p, i) ((p)->Defs && ((p)->Defs[(i) >> 3] & (0x80 >> ((i) & 7))) != 0)
+
+typedef struct
+{
+  UInt32 NumPackStreams;
+  UInt32 NumFolders;
+
+  UInt64 *PackPositions;          // NumPackStreams + 1
+  CSzBitUi32s FolderCRCs;         // NumFolders
+
+  size_t *FoCodersOffsets;        // NumFolders + 1
+  UInt32 *FoStartPackStreamIndex; // NumFolders + 1
+  UInt32 *FoToCoderUnpackSizes;   // NumFolders + 1
+  Byte *FoToMainUnpackSizeIndex;  // NumFolders
+  UInt64 *CoderUnpackSizes;       // for all coders in all folders
+
+  Byte *CodersData;
+
+  UInt64 RangeLimit;
+} CSzAr;
+
+UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex);
+
+SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
+    ILookInStreamPtr stream, UInt64 startPos,
+    Byte *outBuffer, size_t outSize,
+    ISzAllocPtr allocMain);
+
+typedef struct
+{
+  CSzAr db;
+
+  UInt64 startPosAfterHeader;
+  UInt64 dataPos;
+  
+  UInt32 NumFiles;
+
+  UInt64 *UnpackPositions;  // NumFiles + 1
+  // Byte *IsEmptyFiles;
+  Byte *IsDirs;
+  CSzBitUi32s CRCs;
+
+  CSzBitUi32s Attribs;
+  // CSzBitUi32s Parents;
+  CSzBitUi64s MTime;
+  CSzBitUi64s CTime;
+
+  UInt32 *FolderToFile;   // NumFolders + 1
+  UInt32 *FileToFolder;   // NumFiles
+
+  size_t *FileNameOffsets; /* in 2-byte steps */
+  Byte *FileNames;  /* UTF-16-LE */
+} CSzArEx;
+
+#define SzArEx_IsDir(p, i) (SzBitArray_Check((p)->IsDirs, i))
+
+#define SzArEx_GetFileSize(p, i) ((p)->UnpackPositions[(i) + 1] - (p)->UnpackPositions[i])
+
+void SzArEx_Init(CSzArEx *p);
+void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc);
+UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder);
+int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize);
+
+/*
+if dest == NULL, the return value specifies the required size of the buffer,
+  in 16-bit characters, including the null-terminating character.
+if dest != NULL, the return value specifies the number of 16-bit characters that
+  are written to the dest, including the null-terminating character. */
+
+size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
+
+/*
+size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex);
+UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
+*/
+
+
+
+/*
+  SzArEx_Extract 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.
+*/
+
+SRes SzArEx_Extract(
+    const CSzArEx *db,
+    ILookInStreamPtr inStream,
+    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 */
+    ISzAllocPtr allocMain,
+    ISzAllocPtr allocTemp);
+
+
+/*
+SzArEx_Open Errors:
+SZ_ERROR_NO_ARCHIVE
+SZ_ERROR_ARCHIVE
+SZ_ERROR_UNSUPPORTED
+SZ_ERROR_MEM
+SZ_ERROR_CRC
+SZ_ERROR_INPUT_EOF
+SZ_ERROR_FAIL
+*/
+
+SRes SzArEx_Open(CSzArEx *p, ILookInStreamPtr inStream,
+    ISzAllocPtr allocMain, ISzAllocPtr allocTemp);
+
+EXTERN_C_END
+
+#endif

+ 89 - 0
Components/Lzma2/7zAlloc.c

@@ -0,0 +1,89 @@
+/* 7zAlloc.c -- Allocation functions for 7z processing
+2023-03-04 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#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 "7zWindows.h"
+#endif
+*/
+
+#include <stdio.h>
+static int g_allocCount = 0;
+static int g_allocCountTemp = 0;
+
+static void Print_Alloc(const char *s, size_t size, int *counter)
+{
+  const unsigned size2 = (unsigned)size;
+  fprintf(stderr, "\n%s count = %10d : %10u bytes; ", s, *counter, size2);
+  (*counter)++;
+}
+static void Print_Free(const char *s, int *counter)
+{
+  (*counter)--;
+  fprintf(stderr, "\n%s count = %10d", s, *counter);
+}
+#endif
+
+void *SzAlloc(ISzAllocPtr p, size_t size)
+{
+  UNUSED_VAR(p)
+  if (size == 0)
+    return 0;
+  #ifdef SZ_ALLOC_DEBUG
+  Print_Alloc("Alloc", size, &g_allocCount);
+  #endif
+  return malloc(size);
+}
+
+void SzFree(ISzAllocPtr p, void *address)
+{
+  UNUSED_VAR(p)
+  #ifdef SZ_ALLOC_DEBUG
+  if (address)
+    Print_Free("Free ", &g_allocCount);
+  #endif
+  free(address);
+}
+
+void *SzAllocTemp(ISzAllocPtr p, size_t size)
+{
+  UNUSED_VAR(p)
+  if (size == 0)
+    return 0;
+  #ifdef SZ_ALLOC_DEBUG
+  Print_Alloc("Alloc_temp", size, &g_allocCountTemp);
+  /*
+  #ifdef _WIN32
+  return HeapAlloc(GetProcessHeap(), 0, size);
+  #endif
+  */
+  #endif
+  return malloc(size);
+}
+
+void SzFreeTemp(ISzAllocPtr p, void *address)
+{
+  UNUSED_VAR(p)
+  #ifdef SZ_ALLOC_DEBUG
+  if (address)
+    Print_Free("Free_temp ", &g_allocCountTemp);
+  /*
+  #ifdef _WIN32
+  HeapFree(GetProcessHeap(), 0, address);
+  return;
+  #endif
+  */
+  #endif
+  free(address);
+}

+ 19 - 0
Components/Lzma2/7zAlloc.h

@@ -0,0 +1,19 @@
+/* 7zAlloc.h -- Allocation functions
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_7Z_ALLOC_H
+#define ZIP7_INC_7Z_ALLOC_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+void *SzAlloc(ISzAllocPtr p, size_t size);
+void SzFree(ISzAllocPtr p, void *address);
+
+void *SzAllocTemp(ISzAllocPtr p, size_t size);
+void SzFreeTemp(ISzAllocPtr p, void *address);
+
+EXTERN_C_END
+
+#endif

+ 1786 - 0
Components/Lzma2/7zArcIn.c

@@ -0,0 +1,1786 @@
+/* 7zArcIn.c -- 7z Input functions
+2023-09-07 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#include "7z.h"
+#include "7zBuf.h"
+#include "7zCrc.h"
+#include "CpuArch.h"
+
+#define MY_ALLOC(T, p, size, alloc) \
+  { if ((p = (T *)ISzAlloc_Alloc(alloc, (size) * sizeof(T))) == NULL) return SZ_ERROR_MEM; }
+
+#define MY_ALLOC_ZE(T, p, size, alloc) \
+  { if ((size) == 0) p = NULL; else MY_ALLOC(T, p, size, alloc) }
+
+#define MY_ALLOC_AND_CPY(to, size, from, alloc) \
+  { MY_ALLOC(Byte, to, size, alloc); memcpy(to, from, size); }
+
+#define MY_ALLOC_ZE_AND_CPY(to, size, from, alloc) \
+  { if ((size) == 0) to = NULL; else { MY_ALLOC_AND_CPY(to, size, from, alloc) } }
+
+#define k7zMajorVersion 0
+
+enum EIdEnum
+{
+  k7zIdEnd,
+  k7zIdHeader,
+  k7zIdArchiveProperties,
+  k7zIdAdditionalStreamsInfo,
+  k7zIdMainStreamsInfo,
+  k7zIdFilesInfo,
+  k7zIdPackInfo,
+  k7zIdUnpackInfo,
+  k7zIdSubStreamsInfo,
+  k7zIdSize,
+  k7zIdCRC,
+  k7zIdFolder,
+  k7zIdCodersUnpackSize,
+  k7zIdNumUnpackStream,
+  k7zIdEmptyStream,
+  k7zIdEmptyFile,
+  k7zIdAnti,
+  k7zIdName,
+  k7zIdCTime,
+  k7zIdATime,
+  k7zIdMTime,
+  k7zIdWinAttrib,
+  k7zIdComment,
+  k7zIdEncodedHeader,
+  k7zIdStartPos,
+  k7zIdDummy
+  // k7zNtSecure,
+  // k7zParent,
+  // k7zIsReal
+};
+
+const Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
+
+#define SzBitUi32s_INIT(p) { (p)->Defs = NULL; (p)->Vals = NULL; }
+
+static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAllocPtr alloc)
+{
+  if (num == 0)
+  {
+    p->Defs = NULL;
+    p->Vals = NULL;
+  }
+  else
+  {
+    MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc)
+    MY_ALLOC(UInt32, p->Vals, num, alloc)
+  }
+  return SZ_OK;
+}
+
+static void SzBitUi32s_Free(CSzBitUi32s *p, ISzAllocPtr alloc)
+{
+  ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL;
+  ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL;
+}
+
+#define SzBitUi64s_INIT(p) { (p)->Defs = NULL; (p)->Vals = NULL; }
+
+static void SzBitUi64s_Free(CSzBitUi64s *p, ISzAllocPtr alloc)
+{
+  ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL;
+  ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL;
+}
+
+
+static void SzAr_Init(CSzAr *p)
+{
+  p->NumPackStreams = 0;
+  p->NumFolders = 0;
+  
+  p->PackPositions = NULL;
+  SzBitUi32s_INIT(&p->FolderCRCs)
+
+  p->FoCodersOffsets = NULL;
+  p->FoStartPackStreamIndex = NULL;
+  p->FoToCoderUnpackSizes = NULL;
+  p->FoToMainUnpackSizeIndex = NULL;
+  p->CoderUnpackSizes = NULL;
+
+  p->CodersData = NULL;
+
+  p->RangeLimit = 0;
+}
+
+static void SzAr_Free(CSzAr *p, ISzAllocPtr alloc)
+{
+  ISzAlloc_Free(alloc, p->PackPositions);
+  SzBitUi32s_Free(&p->FolderCRCs, alloc);
+ 
+  ISzAlloc_Free(alloc, p->FoCodersOffsets);
+  ISzAlloc_Free(alloc, p->FoStartPackStreamIndex);
+  ISzAlloc_Free(alloc, p->FoToCoderUnpackSizes);
+  ISzAlloc_Free(alloc, p->FoToMainUnpackSizeIndex);
+  ISzAlloc_Free(alloc, p->CoderUnpackSizes);
+  
+  ISzAlloc_Free(alloc, p->CodersData);
+
+  SzAr_Init(p);
+}
+
+
+void SzArEx_Init(CSzArEx *p)
+{
+  SzAr_Init(&p->db);
+  
+  p->NumFiles = 0;
+  p->dataPos = 0;
+  
+  p->UnpackPositions = NULL;
+  p->IsDirs = NULL;
+  
+  p->FolderToFile = NULL;
+  p->FileToFolder = NULL;
+  
+  p->FileNameOffsets = NULL;
+  p->FileNames = NULL;
+  
+  SzBitUi32s_INIT(&p->CRCs)
+  SzBitUi32s_INIT(&p->Attribs)
+  // SzBitUi32s_INIT(&p->Parents)
+  SzBitUi64s_INIT(&p->MTime)
+  SzBitUi64s_INIT(&p->CTime)
+}
+
+void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc)
+{
+  ISzAlloc_Free(alloc, p->UnpackPositions);
+  ISzAlloc_Free(alloc, p->IsDirs);
+
+  ISzAlloc_Free(alloc, p->FolderToFile);
+  ISzAlloc_Free(alloc, p->FileToFolder);
+
+  ISzAlloc_Free(alloc, p->FileNameOffsets);
+  ISzAlloc_Free(alloc, p->FileNames);
+
+  SzBitUi32s_Free(&p->CRCs, alloc);
+  SzBitUi32s_Free(&p->Attribs, alloc);
+  // SzBitUi32s_Free(&p->Parents, alloc);
+  SzBitUi64s_Free(&p->MTime, alloc);
+  SzBitUi64s_Free(&p->CTime, alloc);
+  
+  SzAr_Free(&p->db, alloc);
+  SzArEx_Init(p);
+}
+
+
+static int TestSignatureCandidate(const Byte *testBytes)
+{
+  unsigned i;
+  for (i = 0; i < k7zSignatureSize; i++)
+    if (testBytes[i] != k7zSignature[i])
+      return 0;
+  return 1;
+}
+
+#define SzData_CLEAR(p) { (p)->Data = NULL; (p)->Size = 0; }
+
+#define SZ_READ_BYTE_SD_NOCHECK(_sd_, dest) \
+    (_sd_)->Size--; dest = *(_sd_)->Data++;
+
+#define SZ_READ_BYTE_SD(_sd_, dest) \
+    if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; \
+    SZ_READ_BYTE_SD_NOCHECK(_sd_, dest)
+
+#define SZ_READ_BYTE(dest) SZ_READ_BYTE_SD(sd, dest)
+
+#define SZ_READ_BYTE_2(dest) \
+    if (sd.Size == 0) return SZ_ERROR_ARCHIVE; \
+    sd.Size--; dest = *sd.Data++;
+
+#define SKIP_DATA(sd, size) { sd->Size -= (size_t)(size); sd->Data += (size_t)(size); }
+#define SKIP_DATA2(sd, size) { sd.Size -= (size_t)(size); sd.Data += (size_t)(size); }
+
+#define SZ_READ_32(dest) if (sd.Size < 4) return SZ_ERROR_ARCHIVE; \
+   dest = GetUi32(sd.Data); SKIP_DATA2(sd, 4);
+
+static Z7_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value)
+{
+  Byte firstByte, mask;
+  unsigned i;
+  UInt32 v;
+
+  SZ_READ_BYTE(firstByte)
+  if ((firstByte & 0x80) == 0)
+  {
+    *value = firstByte;
+    return SZ_OK;
+  }
+  SZ_READ_BYTE(v)
+  if ((firstByte & 0x40) == 0)
+  {
+    *value = (((UInt32)firstByte & 0x3F) << 8) | v;
+    return SZ_OK;
+  }
+  SZ_READ_BYTE(mask)
+  *value = v | ((UInt32)mask << 8);
+  mask = 0x20;
+  for (i = 2; i < 8; i++)
+  {
+    Byte b;
+    if ((firstByte & mask) == 0)
+    {
+      const UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1);
+      *value |= (highPart << (8 * i));
+      return SZ_OK;
+    }
+    SZ_READ_BYTE(b)
+    *value |= ((UInt64)b << (8 * i));
+    mask >>= 1;
+  }
+  return SZ_OK;
+}
+
+
+static Z7_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value)
+{
+  Byte firstByte;
+  UInt64 value64;
+  if (sd->Size == 0)
+    return SZ_ERROR_ARCHIVE;
+  firstByte = *sd->Data;
+  if ((firstByte & 0x80) == 0)
+  {
+    *value = firstByte;
+    sd->Data++;
+    sd->Size--;
+    return SZ_OK;
+  }
+  RINOK(ReadNumber(sd, &value64))
+  if (value64 >= (UInt32)0x80000000 - 1)
+    return SZ_ERROR_UNSUPPORTED;
+  if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 4)))
+    return SZ_ERROR_UNSUPPORTED;
+  *value = (UInt32)value64;
+  return SZ_OK;
+}
+
+#define ReadID(sd, value) ReadNumber(sd, value)
+
+static SRes SkipData(CSzData *sd)
+{
+  UInt64 size;
+  RINOK(ReadNumber(sd, &size))
+  if (size > sd->Size)
+    return SZ_ERROR_ARCHIVE;
+  SKIP_DATA(sd, size)
+  return SZ_OK;
+}
+
+static SRes WaitId(CSzData *sd, UInt32 id)
+{
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(ReadID(sd, &type))
+    if (type == id)
+      return SZ_OK;
+    if (type == k7zIdEnd)
+      return SZ_ERROR_ARCHIVE;
+    RINOK(SkipData(sd))
+  }
+}
+
+static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v)
+{
+  const UInt32 numBytes = (numItems + 7) >> 3;
+  if (numBytes > sd->Size)
+    return SZ_ERROR_ARCHIVE;
+  *v = sd->Data;
+  SKIP_DATA(sd, numBytes)
+  return SZ_OK;
+}
+
+static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems)
+{
+  unsigned b = 0;
+  unsigned m = 0;
+  UInt32 sum = 0;
+  for (; numItems != 0; numItems--)
+  {
+    if (m == 0)
+    {
+      b = *bits++;
+      m = 8;
+    }
+    m--;
+    sum += (UInt32)((b >> m) & 1);
+  }
+  return sum;
+}
+
+static Z7_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAllocPtr alloc)
+{
+  Byte allAreDefined;
+  Byte *v2;
+  const UInt32 numBytes = (numItems + 7) >> 3;
+  *v = NULL;
+  SZ_READ_BYTE(allAreDefined)
+  if (numBytes == 0)
+    return SZ_OK;
+  if (allAreDefined == 0)
+  {
+    if (numBytes > sd->Size)
+      return SZ_ERROR_ARCHIVE;
+    MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc)
+    SKIP_DATA(sd, numBytes)
+    return SZ_OK;
+  }
+  MY_ALLOC(Byte, *v, numBytes, alloc)
+  v2 = *v;
+  memset(v2, 0xFF, (size_t)numBytes);
+  {
+    const unsigned numBits = (unsigned)numItems & 7;
+    if (numBits != 0)
+      v2[(size_t)numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits));
+  }
+  return SZ_OK;
+}
+
+static Z7_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc)
+{
+  UInt32 i;
+  CSzData sd;
+  UInt32 *vals;
+  const Byte *defs;
+  MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc)
+  sd = *sd2;
+  defs = crcs->Defs;
+  vals = crcs->Vals;
+  for (i = 0; i < numItems; i++)
+    if (SzBitArray_Check(defs, i))
+    {
+      SZ_READ_32(vals[i])
+    }
+    else
+      vals[i] = 0;
+  *sd2 = sd;
+  return SZ_OK;
+}
+
+static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc)
+{
+  SzBitUi32s_Free(crcs, alloc);
+  RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc))
+  return ReadUi32s(sd, numItems, crcs, alloc);
+}
+
+static SRes SkipBitUi32s(CSzData *sd, UInt32 numItems)
+{
+  Byte allAreDefined;
+  UInt32 numDefined = numItems;
+  SZ_READ_BYTE(allAreDefined)
+  if (!allAreDefined)
+  {
+    const size_t numBytes = (numItems + 7) >> 3;
+    if (numBytes > sd->Size)
+      return SZ_ERROR_ARCHIVE;
+    numDefined = CountDefinedBits(sd->Data, numItems);
+    SKIP_DATA(sd, numBytes)
+  }
+  if (numDefined > (sd->Size >> 2))
+    return SZ_ERROR_ARCHIVE;
+  SKIP_DATA(sd, (size_t)numDefined * 4)
+  return SZ_OK;
+}
+
+static SRes ReadPackInfo(CSzAr *p, CSzData *sd, ISzAllocPtr alloc)
+{
+  RINOK(SzReadNumber32(sd, &p->NumPackStreams))
+
+  RINOK(WaitId(sd, k7zIdSize))
+  MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc)
+  {
+    UInt64 sum = 0;
+    UInt32 i;
+    const UInt32 numPackStreams = p->NumPackStreams;
+    for (i = 0; i < numPackStreams; i++)
+    {
+      UInt64 packSize;
+      p->PackPositions[i] = sum;
+      RINOK(ReadNumber(sd, &packSize))
+      sum += packSize;
+      if (sum < packSize)
+        return SZ_ERROR_ARCHIVE;
+    }
+    p->PackPositions[i] = sum;
+  }
+
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(ReadID(sd, &type))
+    if (type == k7zIdEnd)
+      return SZ_OK;
+    if (type == k7zIdCRC)
+    {
+      /* CRC of packed streams is unused now */
+      RINOK(SkipBitUi32s(sd, p->NumPackStreams))
+      continue;
+    }
+    RINOK(SkipData(sd))
+  }
+}
+
+/*
+static SRes SzReadSwitch(CSzData *sd)
+{
+  Byte external;
+  RINOK(SzReadByte(sd, &external));
+  return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED;
+}
+*/
+
+#define k_NumCodersStreams_in_Folder_MAX (SZ_NUM_BONDS_IN_FOLDER_MAX + SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX)
+
+SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd)
+{
+  UInt32 numCoders, i;
+  UInt32 numInStreams = 0;
+  const Byte *dataStart = sd->Data;
+
+  f->NumCoders = 0;
+  f->NumBonds = 0;
+  f->NumPackStreams = 0;
+  f->UnpackStream = 0;
+  
+  RINOK(SzReadNumber32(sd, &numCoders))
+  if (numCoders == 0 || numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX)
+    return SZ_ERROR_UNSUPPORTED;
+  
+  for (i = 0; i < numCoders; i++)
+  {
+    Byte mainByte;
+    CSzCoderInfo *coder = f->Coders + i;
+    unsigned idSize, j;
+    UInt64 id;
+    
+    SZ_READ_BYTE(mainByte)
+    if ((mainByte & 0xC0) != 0)
+      return SZ_ERROR_UNSUPPORTED;
+    
+    idSize = (unsigned)(mainByte & 0xF);
+    if (idSize > sizeof(id))
+      return SZ_ERROR_UNSUPPORTED;
+    if (idSize > sd->Size)
+      return SZ_ERROR_ARCHIVE;
+    id = 0;
+    for (j = 0; j < idSize; j++)
+    {
+      id = ((id << 8) | *sd->Data);
+      sd->Data++;
+      sd->Size--;
+    }
+    if (id > (UInt32)0xFFFFFFFF)
+      return SZ_ERROR_UNSUPPORTED;
+    coder->MethodID = (UInt32)id;
+    
+    coder->NumStreams = 1;
+    coder->PropsOffset = 0;
+    coder->PropsSize = 0;
+    
+    if ((mainByte & 0x10) != 0)
+    {
+      UInt32 numStreams;
+      
+      RINOK(SzReadNumber32(sd, &numStreams))
+      if (numStreams > k_NumCodersStreams_in_Folder_MAX)
+        return SZ_ERROR_UNSUPPORTED;
+      coder->NumStreams = (Byte)numStreams;
+
+      RINOK(SzReadNumber32(sd, &numStreams))
+      if (numStreams != 1)
+        return SZ_ERROR_UNSUPPORTED;
+    }
+
+    numInStreams += coder->NumStreams;
+
+    if (numInStreams > k_NumCodersStreams_in_Folder_MAX)
+      return SZ_ERROR_UNSUPPORTED;
+
+    if ((mainByte & 0x20) != 0)
+    {
+      UInt32 propsSize = 0;
+      RINOK(SzReadNumber32(sd, &propsSize))
+      if (propsSize > sd->Size)
+        return SZ_ERROR_ARCHIVE;
+      if (propsSize >= 0x80)
+        return SZ_ERROR_UNSUPPORTED;
+      coder->PropsOffset = (size_t)(sd->Data - dataStart);
+      coder->PropsSize = (Byte)propsSize;
+      sd->Data += (size_t)propsSize;
+      sd->Size -= (size_t)propsSize;
+    }
+  }
+
+  /*
+  if (numInStreams == 1 && numCoders == 1)
+  {
+    f->NumPackStreams = 1;
+    f->PackStreams[0] = 0;
+  }
+  else
+  */
+  {
+    Byte streamUsed[k_NumCodersStreams_in_Folder_MAX];
+    UInt32 numBonds, numPackStreams;
+    
+    numBonds = numCoders - 1;
+    if (numInStreams < numBonds)
+      return SZ_ERROR_ARCHIVE;
+    if (numBonds > SZ_NUM_BONDS_IN_FOLDER_MAX)
+      return SZ_ERROR_UNSUPPORTED;
+    f->NumBonds = numBonds;
+    
+    numPackStreams = numInStreams - numBonds;
+    if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX)
+      return SZ_ERROR_UNSUPPORTED;
+    f->NumPackStreams = numPackStreams;
+  
+    for (i = 0; i < numInStreams; i++)
+      streamUsed[i] = False;
+    
+    if (numBonds != 0)
+    {
+      Byte coderUsed[SZ_NUM_CODERS_IN_FOLDER_MAX];
+
+      for (i = 0; i < numCoders; i++)
+        coderUsed[i] = False;
+      
+      for (i = 0; i < numBonds; i++)
+      {
+        CSzBond *bp = f->Bonds + i;
+        
+        RINOK(SzReadNumber32(sd, &bp->InIndex))
+        if (bp->InIndex >= numInStreams || streamUsed[bp->InIndex])
+          return SZ_ERROR_ARCHIVE;
+        streamUsed[bp->InIndex] = True;
+        
+        RINOK(SzReadNumber32(sd, &bp->OutIndex))
+        if (bp->OutIndex >= numCoders || coderUsed[bp->OutIndex])
+          return SZ_ERROR_ARCHIVE;
+        coderUsed[bp->OutIndex] = True;
+      }
+      
+      for (i = 0; i < numCoders; i++)
+        if (!coderUsed[i])
+        {
+          f->UnpackStream = i;
+          break;
+        }
+      
+      if (i == numCoders)
+        return SZ_ERROR_ARCHIVE;
+    }
+    
+    if (numPackStreams == 1)
+    {
+      for (i = 0; i < numInStreams; i++)
+        if (!streamUsed[i])
+          break;
+      if (i == numInStreams)
+        return SZ_ERROR_ARCHIVE;
+      f->PackStreams[0] = i;
+    }
+    else
+      for (i = 0; i < numPackStreams; i++)
+      {
+        UInt32 index;
+        RINOK(SzReadNumber32(sd, &index))
+        if (index >= numInStreams || streamUsed[index])
+          return SZ_ERROR_ARCHIVE;
+        streamUsed[index] = True;
+        f->PackStreams[i] = index;
+      }
+  }
+
+  f->NumCoders = numCoders;
+
+  return SZ_OK;
+}
+
+
+static Z7_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num)
+{
+  CSzData sd;
+  sd = *sd2;
+  for (; num != 0; num--)
+  {
+    Byte firstByte, mask;
+    unsigned i;
+    SZ_READ_BYTE_2(firstByte)
+    if ((firstByte & 0x80) == 0)
+      continue;
+    if ((firstByte & 0x40) == 0)
+    {
+      if (sd.Size == 0)
+        return SZ_ERROR_ARCHIVE;
+      sd.Size--;
+      sd.Data++;
+      continue;
+    }
+    mask = 0x20;
+    for (i = 2; i < 8 && (firstByte & mask) != 0; i++)
+      mask >>= 1;
+    if (i > sd.Size)
+      return SZ_ERROR_ARCHIVE;
+    SKIP_DATA2(sd, i)
+  }
+  *sd2 = sd;
+  return SZ_OK;
+}
+
+
+#define k_Scan_NumCoders_MAX 64
+#define k_Scan_NumCodersStreams_in_Folder_MAX 64
+
+
+static SRes ReadUnpackInfo(CSzAr *p,
+    CSzData *sd2,
+    UInt32 numFoldersMax,
+    const CBuf *tempBufs, UInt32 numTempBufs,
+    ISzAllocPtr alloc)
+{
+  CSzData sd;
+  
+  UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex;
+  const Byte *startBufPtr;
+  Byte external;
+  
+  RINOK(WaitId(sd2, k7zIdFolder))
+  
+  RINOK(SzReadNumber32(sd2, &numFolders))
+  if (numFolders > numFoldersMax)
+    return SZ_ERROR_UNSUPPORTED;
+  p->NumFolders = numFolders;
+
+  SZ_READ_BYTE_SD(sd2, external)
+  if (external == 0)
+    sd = *sd2;
+  else
+  {
+    UInt32 index;
+    RINOK(SzReadNumber32(sd2, &index))
+    if (index >= numTempBufs)
+      return SZ_ERROR_ARCHIVE;
+    sd.Data = tempBufs[index].data;
+    sd.Size = tempBufs[index].size;
+  }
+  
+  MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc)
+  MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc)
+  MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc)
+  MY_ALLOC_ZE(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc)
+  
+  startBufPtr = sd.Data;
+  
+  packStreamIndex = 0;
+  numCodersOutStreams = 0;
+
+  for (fo = 0; fo < numFolders; fo++)
+  {
+    UInt32 numCoders, ci, numInStreams = 0;
+    
+    p->FoCodersOffsets[fo] = (size_t)(sd.Data - startBufPtr);
+    
+    RINOK(SzReadNumber32(&sd, &numCoders))
+    if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX)
+      return SZ_ERROR_UNSUPPORTED;
+    
+    for (ci = 0; ci < numCoders; ci++)
+    {
+      Byte mainByte;
+      unsigned idSize;
+      UInt32 coderInStreams;
+      
+      SZ_READ_BYTE_2(mainByte)
+      if ((mainByte & 0xC0) != 0)
+        return SZ_ERROR_UNSUPPORTED;
+      idSize = (mainByte & 0xF);
+      if (idSize > 8)
+        return SZ_ERROR_UNSUPPORTED;
+      if (idSize > sd.Size)
+        return SZ_ERROR_ARCHIVE;
+      SKIP_DATA2(sd, idSize)
+      
+      coderInStreams = 1;
+      
+      if ((mainByte & 0x10) != 0)
+      {
+        UInt32 coderOutStreams;
+        RINOK(SzReadNumber32(&sd, &coderInStreams))
+        RINOK(SzReadNumber32(&sd, &coderOutStreams))
+        if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX || coderOutStreams != 1)
+          return SZ_ERROR_UNSUPPORTED;
+      }
+      
+      numInStreams += coderInStreams;
+
+      if ((mainByte & 0x20) != 0)
+      {
+        UInt32 propsSize;
+        RINOK(SzReadNumber32(&sd, &propsSize))
+        if (propsSize > sd.Size)
+          return SZ_ERROR_ARCHIVE;
+        SKIP_DATA2(sd, propsSize)
+      }
+    }
+    
+    {
+      UInt32 indexOfMainStream = 0;
+      UInt32 numPackStreams = 1;
+      
+      if (numCoders != 1 || numInStreams != 1)
+      {
+        Byte streamUsed[k_Scan_NumCodersStreams_in_Folder_MAX];
+        Byte coderUsed[k_Scan_NumCoders_MAX];
+    
+        UInt32 i;
+        const UInt32 numBonds = numCoders - 1;
+        if (numInStreams < numBonds)
+          return SZ_ERROR_ARCHIVE;
+        
+        if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX)
+          return SZ_ERROR_UNSUPPORTED;
+        
+        for (i = 0; i < numInStreams; i++)
+          streamUsed[i] = False;
+        for (i = 0; i < numCoders; i++)
+          coderUsed[i] = False;
+        
+        for (i = 0; i < numBonds; i++)
+        {
+          UInt32 index;
+          
+          RINOK(SzReadNumber32(&sd, &index))
+          if (index >= numInStreams || streamUsed[index])
+            return SZ_ERROR_ARCHIVE;
+          streamUsed[index] = True;
+          
+          RINOK(SzReadNumber32(&sd, &index))
+          if (index >= numCoders || coderUsed[index])
+            return SZ_ERROR_ARCHIVE;
+          coderUsed[index] = True;
+        }
+        
+        numPackStreams = numInStreams - numBonds;
+        
+        if (numPackStreams != 1)
+          for (i = 0; i < numPackStreams; i++)
+          {
+            UInt32 index;
+            RINOK(SzReadNumber32(&sd, &index))
+            if (index >= numInStreams || streamUsed[index])
+              return SZ_ERROR_ARCHIVE;
+            streamUsed[index] = True;
+          }
+          
+        for (i = 0; i < numCoders; i++)
+          if (!coderUsed[i])
+          {
+            indexOfMainStream = i;
+            break;
+          }
+ 
+        if (i == numCoders)
+          return SZ_ERROR_ARCHIVE;
+      }
+      
+      p->FoStartPackStreamIndex[fo] = packStreamIndex;
+      p->FoToCoderUnpackSizes[fo] = numCodersOutStreams;
+      p->FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream;
+      numCodersOutStreams += numCoders;
+      if (numCodersOutStreams < numCoders)
+        return SZ_ERROR_UNSUPPORTED;
+      if (numPackStreams > p->NumPackStreams - packStreamIndex)
+        return SZ_ERROR_ARCHIVE;
+      packStreamIndex += numPackStreams;
+    }
+  }
+
+  p->FoToCoderUnpackSizes[fo] = numCodersOutStreams;
+  
+  {
+    const size_t dataSize = (size_t)(sd.Data - startBufPtr);
+    p->FoStartPackStreamIndex[fo] = packStreamIndex;
+    p->FoCodersOffsets[fo] = dataSize;
+    MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc)
+  }
+  
+  if (external != 0)
+  {
+    if (sd.Size != 0)
+      return SZ_ERROR_ARCHIVE;
+    sd = *sd2;
+  }
+  
+  RINOK(WaitId(&sd, k7zIdCodersUnpackSize))
+  
+  MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc)
+  {
+    UInt32 i;
+    for (i = 0; i < numCodersOutStreams; i++)
+    {
+      RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i))
+    }
+  }
+
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(ReadID(&sd, &type))
+    if (type == k7zIdEnd)
+    {
+      *sd2 = sd;
+      return SZ_OK;
+    }
+    if (type == k7zIdCRC)
+    {
+      RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc))
+      continue;
+    }
+    RINOK(SkipData(&sd))
+  }
+}
+
+
+UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex)
+{
+  return p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex] + p->FoToMainUnpackSizeIndex[folderIndex]];
+}
+
+
+typedef struct
+{
+  UInt32 NumTotalSubStreams;
+  UInt32 NumSubDigests;
+  CSzData sdNumSubStreams;
+  CSzData sdSizes;
+  CSzData sdCRCs;
+} CSubStreamInfo;
+
+
+static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi)
+{
+  UInt64 type = 0;
+  UInt32 numSubDigests = 0;
+  const UInt32 numFolders = p->NumFolders;
+  UInt32 numUnpackStreams = numFolders;
+  UInt32 numUnpackSizesInData = 0;
+
+  for (;;)
+  {
+    RINOK(ReadID(sd, &type))
+    if (type == k7zIdNumUnpackStream)
+    {
+      UInt32 i;
+      ssi->sdNumSubStreams.Data = sd->Data;
+      numUnpackStreams = 0;
+      numSubDigests = 0;
+      for (i = 0; i < numFolders; i++)
+      {
+        UInt32 numStreams;
+        RINOK(SzReadNumber32(sd, &numStreams))
+        if (numUnpackStreams > numUnpackStreams + numStreams)
+          return SZ_ERROR_UNSUPPORTED;
+        numUnpackStreams += numStreams;
+        if (numStreams != 0)
+          numUnpackSizesInData += (numStreams - 1);
+        if (numStreams != 1 || !SzBitWithVals_Check(&p->FolderCRCs, i))
+          numSubDigests += numStreams;
+      }
+      ssi->sdNumSubStreams.Size = (size_t)(sd->Data - ssi->sdNumSubStreams.Data);
+      continue;
+    }
+    if (type == k7zIdCRC || type == k7zIdSize || type == k7zIdEnd)
+      break;
+    RINOK(SkipData(sd))
+  }
+
+  if (!ssi->sdNumSubStreams.Data)
+  {
+    numSubDigests = numFolders;
+    if (p->FolderCRCs.Defs)
+      numSubDigests = numFolders - CountDefinedBits(p->FolderCRCs.Defs, numFolders);
+  }
+  
+  ssi->NumTotalSubStreams = numUnpackStreams;
+  ssi->NumSubDigests = numSubDigests;
+
+  if (type == k7zIdSize)
+  {
+    ssi->sdSizes.Data = sd->Data;
+    RINOK(SkipNumbers(sd, numUnpackSizesInData))
+    ssi->sdSizes.Size = (size_t)(sd->Data - ssi->sdSizes.Data);
+    RINOK(ReadID(sd, &type))
+  }
+
+  for (;;)
+  {
+    if (type == k7zIdEnd)
+      return SZ_OK;
+    if (type == k7zIdCRC)
+    {
+      ssi->sdCRCs.Data = sd->Data;
+      RINOK(SkipBitUi32s(sd, numSubDigests))
+      ssi->sdCRCs.Size = (size_t)(sd->Data - ssi->sdCRCs.Data);
+    }
+    else
+    {
+      RINOK(SkipData(sd))
+    }
+    RINOK(ReadID(sd, &type))
+  }
+}
+
+static SRes SzReadStreamsInfo(CSzAr *p,
+    CSzData *sd,
+    UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs,
+    UInt64 *dataOffset,
+    CSubStreamInfo *ssi,
+    ISzAllocPtr alloc)
+{
+  UInt64 type;
+
+  SzData_CLEAR(&ssi->sdSizes)
+  SzData_CLEAR(&ssi->sdCRCs)
+  SzData_CLEAR(&ssi->sdNumSubStreams)
+
+  *dataOffset = 0;
+  RINOK(ReadID(sd, &type))
+  if (type == k7zIdPackInfo)
+  {
+    RINOK(ReadNumber(sd, dataOffset))
+    if (*dataOffset > p->RangeLimit)
+      return SZ_ERROR_ARCHIVE;
+    RINOK(ReadPackInfo(p, sd, alloc))
+    if (p->PackPositions[p->NumPackStreams] > p->RangeLimit - *dataOffset)
+      return SZ_ERROR_ARCHIVE;
+    RINOK(ReadID(sd, &type))
+  }
+  if (type == k7zIdUnpackInfo)
+  {
+    RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc))
+    RINOK(ReadID(sd, &type))
+  }
+  if (type == k7zIdSubStreamsInfo)
+  {
+    RINOK(ReadSubStreamsInfo(p, sd, ssi))
+    RINOK(ReadID(sd, &type))
+  }
+  else
+  {
+    ssi->NumTotalSubStreams = p->NumFolders;
+    // ssi->NumSubDigests = 0;
+  }
+
+  return (type == k7zIdEnd ? SZ_OK : SZ_ERROR_UNSUPPORTED);
+}
+
+static SRes SzReadAndDecodePackedStreams(
+    ILookInStreamPtr inStream,
+    CSzData *sd,
+    CBuf *tempBufs,
+    UInt32 numFoldersMax,
+    UInt64 baseOffset,
+    CSzAr *p,
+    ISzAllocPtr allocTemp)
+{
+  UInt64 dataStartPos;
+  UInt32 fo;
+  CSubStreamInfo ssi;
+
+  RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp))
+  
+  dataStartPos += baseOffset;
+  if (p->NumFolders == 0)
+    return SZ_ERROR_ARCHIVE;
+ 
+  for (fo = 0; fo < p->NumFolders; fo++)
+    Buf_Init(tempBufs + fo);
+  
+  for (fo = 0; fo < p->NumFolders; fo++)
+  {
+    CBuf *tempBuf = tempBufs + fo;
+    const UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo);
+    if ((size_t)unpackSize != unpackSize)
+      return SZ_ERROR_MEM;
+    if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp))
+      return SZ_ERROR_MEM;
+  }
+  
+  for (fo = 0; fo < p->NumFolders; fo++)
+  {
+    const CBuf *tempBuf = tempBufs + fo;
+    RINOK(LookInStream_SeekTo(inStream, dataStartPos))
+    RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp))
+  }
+  
+  return SZ_OK;
+}
+
+static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size_t *offsets)
+{
+  size_t pos = 0;
+  *offsets++ = 0;
+  if (numFiles == 0)
+    return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE;
+  if (size < 2)
+    return SZ_ERROR_ARCHIVE;
+  if (data[size - 2] != 0 || data[size - 1] != 0)
+    return SZ_ERROR_ARCHIVE;
+  do
+  {
+    const Byte *p;
+    if (pos == size)
+      return SZ_ERROR_ARCHIVE;
+    for (p = data + pos;
+      #ifdef _WIN32
+      *(const UInt16 *)(const void *)p != 0
+      #else
+      p[0] != 0 || p[1] != 0
+      #endif
+      ; p += 2);
+    pos = (size_t)(p - data) + 2;
+    *offsets++ = (pos >> 1);
+  }
+  while (--numFiles);
+  return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
+}
+
+static Z7_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num,
+    CSzData *sd2,
+    const CBuf *tempBufs, UInt32 numTempBufs,
+    ISzAllocPtr alloc)
+{
+  CSzData sd;
+  UInt32 i;
+  CNtfsFileTime *vals;
+  Byte *defs;
+  Byte external;
+  
+  RINOK(ReadBitVector(sd2, num, &p->Defs, alloc))
+  
+  SZ_READ_BYTE_SD(sd2, external)
+  if (external == 0)
+    sd = *sd2;
+  else
+  {
+    UInt32 index;
+    RINOK(SzReadNumber32(sd2, &index))
+    if (index >= numTempBufs)
+      return SZ_ERROR_ARCHIVE;
+    sd.Data = tempBufs[index].data;
+    sd.Size = tempBufs[index].size;
+  }
+  
+  MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc)
+  vals = p->Vals;
+  defs = p->Defs;
+  for (i = 0; i < num; i++)
+    if (SzBitArray_Check(defs, i))
+    {
+      if (sd.Size < 8)
+        return SZ_ERROR_ARCHIVE;
+      vals[i].Low = GetUi32(sd.Data);
+      vals[i].High = GetUi32(sd.Data + 4);
+      SKIP_DATA2(sd, 8)
+    }
+    else
+      vals[i].High = vals[i].Low = 0;
+  
+  if (external == 0)
+    *sd2 = sd;
+  
+  return SZ_OK;
+}
+
+
+#define NUM_ADDITIONAL_STREAMS_MAX 8
+
+
+static SRes SzReadHeader2(
+    CSzArEx *p,   /* allocMain */
+    CSzData *sd,
+    ILookInStreamPtr inStream,
+    CBuf *tempBufs, UInt32 *numTempBufs,
+    ISzAllocPtr allocMain,
+    ISzAllocPtr allocTemp
+    )
+{
+  CSubStreamInfo ssi;
+
+{
+  UInt64 type;
+  
+  SzData_CLEAR(&ssi.sdSizes)
+  SzData_CLEAR(&ssi.sdCRCs)
+  SzData_CLEAR(&ssi.sdNumSubStreams)
+
+  ssi.NumSubDigests = 0;
+  ssi.NumTotalSubStreams = 0;
+
+  RINOK(ReadID(sd, &type))
+
+  if (type == k7zIdArchiveProperties)
+  {
+    for (;;)
+    {
+      UInt64 type2;
+      RINOK(ReadID(sd, &type2))
+      if (type2 == k7zIdEnd)
+        break;
+      RINOK(SkipData(sd))
+    }
+    RINOK(ReadID(sd, &type))
+  }
+
+  if (type == k7zIdAdditionalStreamsInfo)
+  {
+    CSzAr tempAr;
+    SRes res;
+    
+    SzAr_Init(&tempAr);
+    tempAr.RangeLimit = p->db.RangeLimit;
+
+    res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX,
+        p->startPosAfterHeader, &tempAr, allocTemp);
+    *numTempBufs = tempAr.NumFolders;
+    SzAr_Free(&tempAr, allocTemp);
+    
+    if (res != SZ_OK)
+      return res;
+    RINOK(ReadID(sd, &type))
+  }
+
+  if (type == k7zIdMainStreamsInfo)
+  {
+    RINOK(SzReadStreamsInfo(&p->db, sd, (UInt32)1 << 30, tempBufs, *numTempBufs,
+        &p->dataPos, &ssi, allocMain))
+    p->dataPos += p->startPosAfterHeader;
+    RINOK(ReadID(sd, &type))
+  }
+
+  if (type == k7zIdEnd)
+  {
+    return SZ_OK;
+  }
+
+  if (type != k7zIdFilesInfo)
+    return SZ_ERROR_ARCHIVE;
+}
+
+{
+  UInt32 numFiles = 0;
+  UInt32 numEmptyStreams = 0;
+  const Byte *emptyStreams = NULL;
+  const Byte *emptyFiles = NULL;
+  
+  RINOK(SzReadNumber32(sd, &numFiles))
+  p->NumFiles = numFiles;
+
+  for (;;)
+  {
+    UInt64 type;
+    UInt64 size;
+    RINOK(ReadID(sd, &type))
+    if (type == k7zIdEnd)
+      break;
+    RINOK(ReadNumber(sd, &size))
+    if (size > sd->Size)
+      return SZ_ERROR_ARCHIVE;
+    
+    if (type >= ((UInt32)1 << 8))
+    {
+      SKIP_DATA(sd, size)
+    }
+    else switch ((unsigned)type)
+    {
+      case k7zIdName:
+      {
+        size_t namesSize;
+        const Byte *namesData;
+        Byte external;
+
+        SZ_READ_BYTE(external)
+        if (external == 0)
+        {
+          namesSize = (size_t)size - 1;
+          namesData = sd->Data;
+        }
+        else
+        {
+          UInt32 index;
+          RINOK(SzReadNumber32(sd, &index))
+          if (index >= *numTempBufs)
+            return SZ_ERROR_ARCHIVE;
+          namesData = (tempBufs)[index].data;
+          namesSize = (tempBufs)[index].size;
+        }
+
+        if ((namesSize & 1) != 0)
+          return SZ_ERROR_ARCHIVE;
+        MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain)
+        MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain)
+        RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets))
+        if (external == 0)
+        {
+          SKIP_DATA(sd, namesSize)
+        }
+        break;
+      }
+      case k7zIdEmptyStream:
+      {
+        RINOK(RememberBitVector(sd, numFiles, &emptyStreams))
+        numEmptyStreams = CountDefinedBits(emptyStreams, numFiles);
+        emptyFiles = NULL;
+        break;
+      }
+      case k7zIdEmptyFile:
+      {
+        RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles))
+        break;
+      }
+      case k7zIdWinAttrib:
+      {
+        Byte external;
+        CSzData sdSwitch;
+        CSzData *sdPtr;
+        SzBitUi32s_Free(&p->Attribs, allocMain);
+        RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain))
+
+        SZ_READ_BYTE(external)
+        if (external == 0)
+          sdPtr = sd;
+        else
+        {
+          UInt32 index;
+          RINOK(SzReadNumber32(sd, &index))
+          if (index >= *numTempBufs)
+            return SZ_ERROR_ARCHIVE;
+          sdSwitch.Data = (tempBufs)[index].data;
+          sdSwitch.Size = (tempBufs)[index].size;
+          sdPtr = &sdSwitch;
+        }
+        RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain))
+        break;
+      }
+      /*
+      case k7zParent:
+      {
+        SzBitUi32s_Free(&p->Parents, allocMain);
+        RINOK(ReadBitVector(sd, numFiles, &p->Parents.Defs, allocMain));
+        RINOK(SzReadSwitch(sd));
+        RINOK(ReadUi32s(sd, numFiles, &p->Parents, allocMain));
+        break;
+      }
+      */
+      case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)) break;
+      case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)) break;
+      default:
+      {
+        SKIP_DATA(sd, size)
+      }
+    }
+  }
+
+  if (numFiles - numEmptyStreams != ssi.NumTotalSubStreams)
+    return SZ_ERROR_ARCHIVE;
+
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(ReadID(sd, &type))
+    if (type == k7zIdEnd)
+      break;
+    RINOK(SkipData(sd))
+  }
+
+  {
+    UInt32 i;
+    UInt32 emptyFileIndex = 0;
+    UInt32 folderIndex = 0;
+    UInt32 remSubStreams = 0;
+    UInt32 numSubStreams = 0;
+    UInt64 unpackPos = 0;
+    const Byte *digestsDefs = NULL;
+    const Byte *digestsVals = NULL;
+    UInt32 digestIndex = 0;
+    Byte isDirMask = 0;
+    Byte crcMask = 0;
+    Byte mask = 0x80;
+    
+    MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain)
+    MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain)
+    MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain)
+    MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain)
+
+    RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain))
+
+    if (ssi.sdCRCs.Size != 0)
+    {
+      Byte allDigestsDefined = 0;
+      SZ_READ_BYTE_SD_NOCHECK(&ssi.sdCRCs, allDigestsDefined)
+      if (allDigestsDefined)
+        digestsVals = ssi.sdCRCs.Data;
+      else
+      {
+        const size_t numBytes = (ssi.NumSubDigests + 7) >> 3;
+        digestsDefs = ssi.sdCRCs.Data;
+        digestsVals = digestsDefs + numBytes;
+      }
+    }
+
+    for (i = 0; i < numFiles; i++, mask >>= 1)
+    {
+      if (mask == 0)
+      {
+        const UInt32 byteIndex = (i - 1) >> 3;
+        p->IsDirs[byteIndex] = isDirMask;
+        p->CRCs.Defs[byteIndex] = crcMask;
+        isDirMask = 0;
+        crcMask = 0;
+        mask = 0x80;
+      }
+
+      p->UnpackPositions[i] = unpackPos;
+      p->CRCs.Vals[i] = 0;
+      
+      if (emptyStreams && SzBitArray_Check(emptyStreams, i))
+      {
+        if (emptyFiles)
+        {
+          if (!SzBitArray_Check(emptyFiles, emptyFileIndex))
+            isDirMask |= mask;
+          emptyFileIndex++;
+        }
+        else
+          isDirMask |= mask;
+        if (remSubStreams == 0)
+        {
+          p->FileToFolder[i] = (UInt32)-1;
+          continue;
+        }
+      }
+      
+      if (remSubStreams == 0)
+      {
+        for (;;)
+        {
+          if (folderIndex >= p->db.NumFolders)
+            return SZ_ERROR_ARCHIVE;
+          p->FolderToFile[folderIndex] = i;
+          numSubStreams = 1;
+          if (ssi.sdNumSubStreams.Data)
+          {
+            RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams))
+          }
+          remSubStreams = numSubStreams;
+          if (numSubStreams != 0)
+            break;
+          {
+            const UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+            unpackPos += folderUnpackSize;
+            if (unpackPos < folderUnpackSize)
+              return SZ_ERROR_ARCHIVE;
+          }
+          folderIndex++;
+        }
+      }
+      
+      p->FileToFolder[i] = folderIndex;
+      
+      if (emptyStreams && SzBitArray_Check(emptyStreams, i))
+        continue;
+      
+      if (--remSubStreams == 0)
+      {
+        const UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+        const UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]];
+        if (folderUnpackSize < unpackPos - startFolderUnpackPos)
+          return SZ_ERROR_ARCHIVE;
+        unpackPos = startFolderUnpackPos + folderUnpackSize;
+        if (unpackPos < folderUnpackSize)
+          return SZ_ERROR_ARCHIVE;
+
+        if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, folderIndex))
+        {
+          p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex];
+          crcMask |= mask;
+        }
+        folderIndex++;
+      }
+      else
+      {
+        UInt64 v;
+        RINOK(ReadNumber(&ssi.sdSizes, &v))
+        unpackPos += v;
+        if (unpackPos < v)
+          return SZ_ERROR_ARCHIVE;
+      }
+      if ((crcMask & mask) == 0 && digestsVals)
+      {
+        if (!digestsDefs || SzBitArray_Check(digestsDefs, digestIndex))
+        {
+          p->CRCs.Vals[i] = GetUi32(digestsVals);
+          digestsVals += 4;
+          crcMask |= mask;
+        }
+        digestIndex++;
+      }
+    }
+
+    if (mask != 0x80)
+    {
+      const UInt32 byteIndex = (i - 1) >> 3;
+      p->IsDirs[byteIndex] = isDirMask;
+      p->CRCs.Defs[byteIndex] = crcMask;
+    }
+    
+    p->UnpackPositions[i] = unpackPos;
+
+    if (remSubStreams != 0)
+      return SZ_ERROR_ARCHIVE;
+
+    for (;;)
+    {
+      p->FolderToFile[folderIndex] = i;
+      if (folderIndex >= p->db.NumFolders)
+        break;
+      if (!ssi.sdNumSubStreams.Data)
+        return SZ_ERROR_ARCHIVE;
+      RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams))
+      if (numSubStreams != 0)
+        return SZ_ERROR_ARCHIVE;
+      /*
+      {
+        UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+        unpackPos += folderUnpackSize;
+        if (unpackPos < folderUnpackSize)
+          return SZ_ERROR_ARCHIVE;
+      }
+      */
+      folderIndex++;
+    }
+
+    if (ssi.sdNumSubStreams.Data && ssi.sdNumSubStreams.Size != 0)
+      return SZ_ERROR_ARCHIVE;
+  }
+}
+  return SZ_OK;
+}
+
+
+static SRes SzReadHeader(
+    CSzArEx *p,
+    CSzData *sd,
+    ILookInStreamPtr inStream,
+    ISzAllocPtr allocMain,
+    ISzAllocPtr allocTemp)
+{
+  UInt32 i;
+  UInt32 numTempBufs = 0;
+  SRes res;
+  CBuf tempBufs[NUM_ADDITIONAL_STREAMS_MAX];
+
+  for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++)
+    Buf_Init(tempBufs + i);
+  
+  res = SzReadHeader2(p, sd, inStream,
+      tempBufs, &numTempBufs,
+      allocMain, allocTemp);
+  
+  for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++)
+    Buf_Free(tempBufs + i, allocTemp);
+
+  RINOK(res)
+
+  if (sd->Size != 0)
+    return SZ_ERROR_FAIL;
+
+  return res;
+}
+
+static SRes SzArEx_Open2(
+    CSzArEx *p,
+    ILookInStreamPtr inStream,
+    ISzAllocPtr allocMain,
+    ISzAllocPtr allocTemp)
+{
+  Byte header[k7zStartHeaderSize];
+  Int64 startArcPos;
+  UInt64 nextHeaderOffset, nextHeaderSize;
+  size_t nextHeaderSizeT;
+  UInt32 nextHeaderCRC;
+  CBuf buf;
+  SRes res;
+
+  startArcPos = 0;
+  RINOK(ILookInStream_Seek(inStream, &startArcPos, SZ_SEEK_CUR))
+
+  RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE))
+
+  if (!TestSignatureCandidate(header))
+    return SZ_ERROR_NO_ARCHIVE;
+  if (header[6] != k7zMajorVersion)
+    return SZ_ERROR_UNSUPPORTED;
+
+  nextHeaderOffset = GetUi64(header + 12);
+  nextHeaderSize = GetUi64(header + 20);
+  nextHeaderCRC = GetUi32(header + 28);
+
+  p->startPosAfterHeader = (UInt64)startArcPos + k7zStartHeaderSize;
+  
+  if (CrcCalc(header + 12, 20) != GetUi32(header + 8))
+    return SZ_ERROR_CRC;
+
+  p->db.RangeLimit = nextHeaderOffset;
+
+  nextHeaderSizeT = (size_t)nextHeaderSize;
+  if (nextHeaderSizeT != nextHeaderSize)
+    return SZ_ERROR_MEM;
+  if (nextHeaderSizeT == 0)
+    return SZ_OK;
+  if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize ||
+      nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize)
+    return SZ_ERROR_NO_ARCHIVE;
+
+  {
+    Int64 pos = 0;
+    RINOK(ILookInStream_Seek(inStream, &pos, SZ_SEEK_END))
+    if ((UInt64)pos < (UInt64)startArcPos + nextHeaderOffset ||
+        (UInt64)pos < (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset ||
+        (UInt64)pos < (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize)
+      return SZ_ERROR_INPUT_EOF;
+  }
+
+  RINOK(LookInStream_SeekTo(inStream, (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset))
+
+  if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp))
+    return SZ_ERROR_MEM;
+
+  res = LookInStream_Read(inStream, buf.data, nextHeaderSizeT);
+  
+  if (res == SZ_OK)
+  {
+    res = SZ_ERROR_ARCHIVE;
+    if (CrcCalc(buf.data, nextHeaderSizeT) == nextHeaderCRC)
+    {
+      CSzData sd;
+      UInt64 type;
+      sd.Data = buf.data;
+      sd.Size = buf.size;
+      
+      res = ReadID(&sd, &type);
+      
+      if (res == SZ_OK && type == k7zIdEncodedHeader)
+      {
+        CSzAr tempAr;
+        CBuf tempBuf;
+        Buf_Init(&tempBuf);
+        
+        SzAr_Init(&tempAr);
+        tempAr.RangeLimit = p->db.RangeLimit;
+
+        res = SzReadAndDecodePackedStreams(inStream, &sd, &tempBuf, 1, p->startPosAfterHeader, &tempAr, allocTemp);
+        SzAr_Free(&tempAr, allocTemp);
+       
+        if (res != SZ_OK)
+        {
+          Buf_Free(&tempBuf, allocTemp);
+        }
+        else
+        {
+          Buf_Free(&buf, allocTemp);
+          buf.data = tempBuf.data;
+          buf.size = tempBuf.size;
+          sd.Data = buf.data;
+          sd.Size = buf.size;
+          res = ReadID(&sd, &type);
+        }
+      }
+  
+      if (res == SZ_OK)
+      {
+        if (type == k7zIdHeader)
+        {
+          /*
+          CSzData sd2;
+          unsigned ttt;
+          for (ttt = 0; ttt < 40000; ttt++)
+          {
+            SzArEx_Free(p, allocMain);
+            sd2 = sd;
+            res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp);
+            if (res != SZ_OK)
+              break;
+          }
+          */
+          res = SzReadHeader(p, &sd, inStream, allocMain, allocTemp);
+        }
+        else
+          res = SZ_ERROR_UNSUPPORTED;
+      }
+    }
+  }
+ 
+  Buf_Free(&buf, allocTemp);
+  return res;
+}
+
+
+SRes SzArEx_Open(CSzArEx *p, ILookInStreamPtr inStream,
+    ISzAllocPtr allocMain, ISzAllocPtr allocTemp)
+{
+  const SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp);
+  if (res != SZ_OK)
+    SzArEx_Free(p, allocMain);
+  return res;
+}
+
+
+SRes SzArEx_Extract(
+    const CSzArEx *p,
+    ILookInStreamPtr inStream,
+    UInt32 fileIndex,
+    UInt32 *blockIndex,
+    Byte **tempBuf,
+    size_t *outBufferSize,
+    size_t *offset,
+    size_t *outSizeProcessed,
+    ISzAllocPtr allocMain,
+    ISzAllocPtr allocTemp)
+{
+  const UInt32 folderIndex = p->FileToFolder[fileIndex];
+  SRes res = SZ_OK;
+  
+  *offset = 0;
+  *outSizeProcessed = 0;
+  
+  if (folderIndex == (UInt32)-1)
+  {
+    ISzAlloc_Free(allocMain, *tempBuf);
+    *blockIndex = folderIndex;
+    *tempBuf = NULL;
+    *outBufferSize = 0;
+    return SZ_OK;
+  }
+
+  if (*tempBuf == NULL || *blockIndex != folderIndex)
+  {
+    const UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+    /*
+    UInt64 unpackSizeSpec =
+        p->UnpackPositions[p->FolderToFile[(size_t)folderIndex + 1]] -
+        p->UnpackPositions[p->FolderToFile[folderIndex]];
+    */
+    const size_t unpackSize = (size_t)unpackSizeSpec;
+
+    if (unpackSize != unpackSizeSpec)
+      return SZ_ERROR_MEM;
+    *blockIndex = folderIndex;
+    ISzAlloc_Free(allocMain, *tempBuf);
+    *tempBuf = NULL;
+    
+    if (res == SZ_OK)
+    {
+      *outBufferSize = unpackSize;
+      if (unpackSize != 0)
+      {
+        *tempBuf = (Byte *)ISzAlloc_Alloc(allocMain, unpackSize);
+        if (*tempBuf == NULL)
+          res = SZ_ERROR_MEM;
+      }
+  
+      if (res == SZ_OK)
+      {
+        res = SzAr_DecodeFolder(&p->db, folderIndex,
+            inStream, p->dataPos, *tempBuf, unpackSize, allocTemp);
+      }
+    }
+  }
+
+  if (res == SZ_OK)
+  {
+    const UInt64 unpackPos = p->UnpackPositions[fileIndex];
+    *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderToFile[folderIndex]]);
+    *outSizeProcessed = (size_t)(p->UnpackPositions[(size_t)fileIndex + 1] - unpackPos);
+    if (*offset + *outSizeProcessed > *outBufferSize)
+      return SZ_ERROR_FAIL;
+    if (SzBitWithVals_Check(&p->CRCs, fileIndex))
+      if (CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex])
+        res = SZ_ERROR_CRC;
+  }
+
+  return res;
+}
+
+
+size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest)
+{
+  const size_t offs = p->FileNameOffsets[fileIndex];
+  const size_t len = p->FileNameOffsets[fileIndex + 1] - offs;
+  if (dest != 0)
+  {
+    size_t i;
+    const Byte *src = p->FileNames + offs * 2;
+    for (i = 0; i < len; i++)
+      dest[i] = GetUi16(src + i * 2);
+  }
+  return len;
+}
+
+/*
+size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex)
+{
+  size_t len;
+  if (!p->FileNameOffsets)
+    return 1;
+  len = 0;
+  for (;;)
+  {
+    UInt32 parent = (UInt32)(Int32)-1;
+    len += p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
+    if SzBitWithVals_Check(&p->Parents, fileIndex)
+      parent = p->Parents.Vals[fileIndex];
+    if (parent == (UInt32)(Int32)-1)
+      return len;
+    fileIndex = parent;
+  }
+}
+
+UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest)
+{
+  BoolInt needSlash;
+  if (!p->FileNameOffsets)
+  {
+    *(--dest) = 0;
+    return dest;
+  }
+  needSlash = False;
+  for (;;)
+  {
+    UInt32 parent = (UInt32)(Int32)-1;
+    size_t curLen = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
+    SzArEx_GetFileNameUtf16(p, fileIndex, dest - curLen);
+    if (needSlash)
+      *(dest - 1) = '/';
+    needSlash = True;
+    dest -= curLen;
+
+    if SzBitWithVals_Check(&p->Parents, fileIndex)
+      parent = p->Parents.Vals[fileIndex];
+    if (parent == (UInt32)(Int32)-1)
+      return dest;
+    fileIndex = parent;
+  }
+}
+*/

+ 36 - 0
Components/Lzma2/7zBuf.c

@@ -0,0 +1,36 @@
+/* 7zBuf.c -- Byte Buffer
+2017-04-03 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "7zBuf.h"
+
+void Buf_Init(CBuf *p)
+{
+  p->data = 0;
+  p->size = 0;
+}
+
+int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc)
+{
+  p->size = 0;
+  if (size == 0)
+  {
+    p->data = 0;
+    return 1;
+  }
+  p->data = (Byte *)ISzAlloc_Alloc(alloc, size);
+  if (p->data)
+  {
+    p->size = size;
+    return 1;
+  }
+  return 0;
+}
+
+void Buf_Free(CBuf *p, ISzAllocPtr alloc)
+{
+  ISzAlloc_Free(alloc, p->data);
+  p->data = 0;
+  p->size = 0;
+}

+ 35 - 0
Components/Lzma2/7zBuf.h

@@ -0,0 +1,35 @@
+/* 7zBuf.h -- Byte Buffer
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_7Z_BUF_H
+#define ZIP7_INC_7Z_BUF_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+typedef struct
+{
+  Byte *data;
+  size_t size;
+} CBuf;
+
+void Buf_Init(CBuf *p);
+int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc);
+void Buf_Free(CBuf *p, ISzAllocPtr alloc);
+
+typedef struct
+{
+  Byte *data;
+  size_t size;
+  size_t pos;
+} CDynBuf;
+
+void DynBuf_Construct(CDynBuf *p);
+void DynBuf_SeekToBeg(CDynBuf *p);
+int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc);
+void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc);
+
+EXTERN_C_END
+
+#endif

+ 187 - 0
Components/Lzma2/7zC.txt

@@ -0,0 +1,187 @@
+7z ANSI-C Decoder 9.35
+----------------------
+
+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
+-------
+
+7z ANSI-C Decoder is part of the LZMA SDK.
+LZMA SDK is written and placed in the public domain by Igor Pavlov.
+
+Files
+---------------------
+
+7zDecode.*   - Low level 7z decoding
+7zExtract.*  - High level 7z decoding
+7zHeader.*   - .7z format constants
+7zIn.*       - .7z archive opening
+7zItem.*     - .7z structures
+7zMain.c     - Test application
+
+
+How To Use
+----------
+
+You can create .7z archive with 7z.exe, 7za.exe or 7zr.exe:
+
+  7z.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
+----------------------
+
+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 ILookInStream interface */
+  CSzArEx db;              /* 7z archive database structure */
+  ISzAlloc allocImp;       /* memory functions for main pool */
+  ISzAlloc allocTempImp;   /* memory functions for temporary pool */
+
+2) call CrcGenerateTable(); function to initialize CRC structures.
+
+3) call SzArEx_Init(&db); function to initialize db structures.
+
+4) call SzArEx_Open(&db, inStream, &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.
+SzArEx_Open function allocates and frees temporary structures by "allocTemp" functions.
+
+5) List items or Extract items
+
+  Listing code:
+  ~~~~~~~~~~~~~
+
+    Use SzArEx_GetFileNameUtf16 function. Look example code in C\Util\7z\7zMain.c file. 
+    
+
+  Extracting code:
+  ~~~~~~~~~~~~~~~~
+
+  SZ_RESULT SzAr_Extract(
+    CArchiveDatabaseEx *db,
+    ILookInStream *inStream, 
+    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 SzArEx_Free(&db, allocImp.Free) to free allocated items in "db".
+
+
+
+
+Memory requirements for .7z decoding 
+------------------------------------
+
+Memory usage for Archive opening:
+  - Temporary pool:
+     - 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 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. 
+  
+
+7z Decoder doesn't allocate memory for compressed blocks. 
+Instead of this, you must allocate buffer with desired 
+size before calling 7z Decoder. Use 7zMain.c as example.
+
+
+Defines
+-------
+
+_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/sdk.html
+http://www.7-zip.org/support.html

+ 420 - 0
Components/Lzma2/7zCrc.c

@@ -0,0 +1,420 @@
+/* 7zCrc.c -- CRC32 calculation and init
+2024-03-01 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "7zCrc.h"
+#include "CpuArch.h"
+
+// for debug:
+// #define __ARM_FEATURE_CRC32 1
+
+#ifdef __ARM_FEATURE_CRC32
+// #pragma message("__ARM_FEATURE_CRC32")
+#define Z7_CRC_HW_FORCE
+#endif
+
+// #define Z7_CRC_DEBUG_BE
+#ifdef Z7_CRC_DEBUG_BE
+#undef MY_CPU_LE
+#define MY_CPU_BE
+#endif
+
+#ifdef Z7_CRC_HW_FORCE
+  #define Z7_CRC_NUM_TABLES_USE  1
+#else
+#ifdef Z7_CRC_NUM_TABLES
+  #define Z7_CRC_NUM_TABLES_USE  Z7_CRC_NUM_TABLES
+#else
+  #define Z7_CRC_NUM_TABLES_USE  12
+#endif
+#endif
+
+#if Z7_CRC_NUM_TABLES_USE < 1
+  #error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES
+#endif
+
+#if defined(MY_CPU_LE) || (Z7_CRC_NUM_TABLES_USE == 1)
+  #define Z7_CRC_NUM_TABLES_TOTAL  Z7_CRC_NUM_TABLES_USE
+#else
+  #define Z7_CRC_NUM_TABLES_TOTAL  (Z7_CRC_NUM_TABLES_USE + 1)
+#endif
+
+#ifndef Z7_CRC_HW_FORCE
+
+#if Z7_CRC_NUM_TABLES_USE == 1 \
+   || (!defined(MY_CPU_LE) && !defined(MY_CPU_BE))
+#define CRC_UPDATE_BYTE_2(crc, b)   (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+#define Z7_CRC_UPDATE_T1_FUNC_NAME  CrcUpdateGT1
+static UInt32 Z7_FASTCALL Z7_CRC_UPDATE_T1_FUNC_NAME(UInt32 v, const void *data, size_t size)
+{
+  const UInt32 *table = g_CrcTable;
+  const Byte *p = (const Byte *)data;
+  const Byte *lim = p + size;
+  for (; p != lim; p++)
+    v = CRC_UPDATE_BYTE_2(v, *p);
+  return v;
+}
+#endif
+
+
+#if Z7_CRC_NUM_TABLES_USE != 1
+#ifndef MY_CPU_BE
+  #define FUNC_NAME_LE_2(s)   CrcUpdateT ## s
+  #define FUNC_NAME_LE_1(s)   FUNC_NAME_LE_2(s)
+  #define FUNC_NAME_LE        FUNC_NAME_LE_1(Z7_CRC_NUM_TABLES_USE)
+  UInt32 Z7_FASTCALL FUNC_NAME_LE (UInt32 v, const void *data, size_t size, const UInt32 *table);
+#endif
+#ifndef MY_CPU_LE
+  #define FUNC_NAME_BE_2(s)   CrcUpdateT1_BeT ## s
+  #define FUNC_NAME_BE_1(s)   FUNC_NAME_BE_2(s)
+  #define FUNC_NAME_BE        FUNC_NAME_BE_1(Z7_CRC_NUM_TABLES_USE)
+  UInt32 Z7_FASTCALL FUNC_NAME_BE (UInt32 v, const void *data, size_t size, const UInt32 *table);
+#endif
+#endif
+
+#endif // Z7_CRC_HW_FORCE
+
+/* ---------- hardware CRC ---------- */
+
+#ifdef MY_CPU_LE
+
+#if defined(MY_CPU_ARM_OR_ARM64)
+// #pragma message("ARM*")
+
+  #if (defined(__clang__) && (__clang_major__ >= 3)) \
+     || defined(__GNUC__) && (__GNUC__ >= 6) && defined(MY_CPU_ARM64) \
+     || defined(__GNUC__) && (__GNUC__ >= 8)
+      #if !defined(__ARM_FEATURE_CRC32)
+//        #pragma message("!defined(__ARM_FEATURE_CRC32)")
+Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
+        #define __ARM_FEATURE_CRC32 1
+Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
+        #define Z7_ARM_FEATURE_CRC32_WAS_SET
+        #if defined(__clang__)
+          #if defined(MY_CPU_ARM64)
+            #define ATTRIB_CRC __attribute__((__target__("crc")))
+          #else
+            #define ATTRIB_CRC __attribute__((__target__("armv8-a,crc")))
+          #endif
+        #else
+          #if defined(MY_CPU_ARM64)
+#if !defined(Z7_GCC_VERSION) || (Z7_GCC_VERSION >= 60000)
+            #define ATTRIB_CRC __attribute__((__target__("+crc")))
+#endif
+          #else
+#if !defined(Z7_GCC_VERSION) || (__GNUC__  >= 8)
+#if defined(__ARM_FP) && __GNUC__ >= 8
+// for -mfloat-abi=hard: similar to <arm_acle.h>
+            #define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc+simd")))
+#else
+            #define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc")))
+#endif
+#endif
+          #endif
+        #endif
+      #endif
+      #if defined(__ARM_FEATURE_CRC32)
+      // #pragma message("<arm_acle.h>")
+/*
+arm_acle.h (GGC):
+    before Nov 17, 2017:
+#ifdef __ARM_FEATURE_CRC32
+
+    Nov 17, 2017: gcc10.0  (gcc 9.2.0) checked"
+#if __ARM_ARCH >= 8
+#pragma GCC target ("arch=armv8-a+crc")
+
+    Aug 22, 2019: GCC 8.4?, 9.2.1, 10.1:
+#ifdef __ARM_FEATURE_CRC32
+#ifdef __ARM_FP
+#pragma GCC target ("arch=armv8-a+crc+simd")
+#else
+#pragma GCC target ("arch=armv8-a+crc")
+#endif
+*/
+#if defined(__ARM_ARCH) && __ARM_ARCH < 8
+#if defined(Z7_GCC_VERSION) && (__GNUC__ ==   8) && (Z7_GCC_VERSION <  80400) \
+ || defined(Z7_GCC_VERSION) && (__GNUC__ ==   9) && (Z7_GCC_VERSION <  90201) \
+ || defined(Z7_GCC_VERSION) && (__GNUC__ ==  10) && (Z7_GCC_VERSION < 100100)
+Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
+// #pragma message("#define __ARM_ARCH 8")
+#undef  __ARM_ARCH
+#define __ARM_ARCH 8
+Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
+#endif
+#endif
+        #define Z7_CRC_HW_USE
+        #include <arm_acle.h>
+      #endif
+  #elif defined(_MSC_VER)
+    #if defined(MY_CPU_ARM64)
+    #if (_MSC_VER >= 1910)
+    #ifdef __clang__
+       // #define Z7_CRC_HW_USE
+       // #include <arm_acle.h>
+    #else
+       #define Z7_CRC_HW_USE
+       #include <intrin.h>
+    #endif
+    #endif
+    #endif
+  #endif
+
+#else // non-ARM*
+
+// #define Z7_CRC_HW_USE // for debug : we can test HW-branch of code
+#ifdef Z7_CRC_HW_USE
+#include "7zCrcEmu.h"
+#endif
+
+#endif // non-ARM*
+
+
+
+#if defined(Z7_CRC_HW_USE)
+
+// #pragma message("USE ARM HW CRC")
+
+#ifdef MY_CPU_64BIT
+  #define CRC_HW_WORD_TYPE  UInt64
+  #define CRC_HW_WORD_FUNC  __crc32d
+#else
+  #define CRC_HW_WORD_TYPE  UInt32
+  #define CRC_HW_WORD_FUNC  __crc32w
+#endif
+
+#define CRC_HW_UNROLL_BYTES (sizeof(CRC_HW_WORD_TYPE) * 4)
+
+#ifdef ATTRIB_CRC
+  ATTRIB_CRC
+#endif
+Z7_NO_INLINE
+#ifdef Z7_CRC_HW_FORCE
+         UInt32 Z7_FASTCALL CrcUpdate
+#else
+  static UInt32 Z7_FASTCALL CrcUpdate_HW
+#endif
+    (UInt32 v, const void *data, size_t size)
+{
+  const Byte *p = (const Byte *)data;
+  for (; size != 0 && ((unsigned)(ptrdiff_t)p & (CRC_HW_UNROLL_BYTES - 1)) != 0; size--)
+    v = __crc32b(v, *p++);
+  if (size >= CRC_HW_UNROLL_BYTES)
+  {
+    const Byte *lim = p + size;
+    size &= CRC_HW_UNROLL_BYTES - 1;
+    lim -= size;
+    do
+    {
+      v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p));
+      v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p + sizeof(CRC_HW_WORD_TYPE)));
+      p += 2 * sizeof(CRC_HW_WORD_TYPE);
+      v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p));
+      v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p + sizeof(CRC_HW_WORD_TYPE)));
+      p += 2 * sizeof(CRC_HW_WORD_TYPE);
+    }
+    while (p != lim);
+  }
+  
+  for (; size != 0; size--)
+    v = __crc32b(v, *p++);
+
+  return v;
+}
+
+#ifdef Z7_ARM_FEATURE_CRC32_WAS_SET
+Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
+#undef __ARM_FEATURE_CRC32
+Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
+#undef Z7_ARM_FEATURE_CRC32_WAS_SET
+#endif
+
+#endif // defined(Z7_CRC_HW_USE)
+#endif // MY_CPU_LE
+
+
+
+#ifndef Z7_CRC_HW_FORCE
+
+#if defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME)
+/*
+typedef UInt32 (Z7_FASTCALL *Z7_CRC_UPDATE_WITH_TABLE_FUNC)
+    (UInt32 v, const void *data, size_t size, const UInt32 *table);
+Z7_CRC_UPDATE_WITH_TABLE_FUNC g_CrcUpdate;
+*/
+static unsigned g_Crc_Algo;
+#if (!defined(MY_CPU_LE) && !defined(MY_CPU_BE))
+static unsigned g_Crc_Be;
+#endif
+#endif // defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME)
+
+
+
+Z7_NO_INLINE
+#ifdef Z7_CRC_HW_USE
+  static UInt32 Z7_FASTCALL CrcUpdate_Base
+#else
+         UInt32 Z7_FASTCALL CrcUpdate
+#endif
+    (UInt32 crc, const void *data, size_t size)
+{
+#if Z7_CRC_NUM_TABLES_USE == 1
+    return Z7_CRC_UPDATE_T1_FUNC_NAME(crc, data, size);
+#else // Z7_CRC_NUM_TABLES_USE != 1
+#ifdef Z7_CRC_UPDATE_T1_FUNC_NAME
+  if (g_Crc_Algo == 1)
+    return Z7_CRC_UPDATE_T1_FUNC_NAME(crc, data, size);
+#endif
+
+#ifdef MY_CPU_LE
+    return FUNC_NAME_LE(crc, data, size, g_CrcTable);
+#elif defined(MY_CPU_BE)
+    return FUNC_NAME_BE(crc, data, size, g_CrcTable);
+#else
+  if (g_Crc_Be)
+    return FUNC_NAME_BE(crc, data, size, g_CrcTable);
+  else
+    return FUNC_NAME_LE(crc, data, size, g_CrcTable);
+#endif
+#endif // Z7_CRC_NUM_TABLES_USE != 1
+}
+
+
+#ifdef Z7_CRC_HW_USE
+Z7_NO_INLINE
+UInt32 Z7_FASTCALL CrcUpdate(UInt32 crc, const void *data, size_t size)
+{
+  if (g_Crc_Algo == 0)
+    return CrcUpdate_HW(crc, data, size);
+  return CrcUpdate_Base(crc, data, size);
+}
+#endif
+
+#endif // !defined(Z7_CRC_HW_FORCE)
+
+
+
+UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size)
+{
+  return CrcUpdate(CRC_INIT_VAL, data, size) ^ CRC_INIT_VAL;
+}
+
+
+MY_ALIGN(64)
+UInt32 g_CrcTable[256 * Z7_CRC_NUM_TABLES_TOTAL];
+
+
+void Z7_FASTCALL CrcGenerateTable(void)
+{
+  UInt32 i;
+  for (i = 0; i < 256; i++)
+  {
+#if defined(Z7_CRC_HW_FORCE)
+    g_CrcTable[i] = __crc32b(i, 0);
+#else
+    #define kCrcPoly 0xEDB88320
+    UInt32 r = i;
+    unsigned j;
+    for (j = 0; j < 8; j++)
+      r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1)));
+    g_CrcTable[i] = r;
+#endif
+  }
+  for (i = 256; i < 256 * Z7_CRC_NUM_TABLES_USE; i++)
+  {
+    const UInt32 r = g_CrcTable[(size_t)i - 256];
+    g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
+  }
+
+#if !defined(Z7_CRC_HW_FORCE) && \
+    (defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME) || defined(MY_CPU_BE))
+
+#if Z7_CRC_NUM_TABLES_USE <= 1
+    g_Crc_Algo = 1;
+#else // Z7_CRC_NUM_TABLES_USE <= 1
+
+#if defined(MY_CPU_LE)
+    g_Crc_Algo = Z7_CRC_NUM_TABLES_USE;
+#else // !defined(MY_CPU_LE)
+  {
+#ifndef MY_CPU_BE
+    UInt32 k = 0x01020304;
+    const Byte *p = (const Byte *)&k;
+    if (p[0] == 4 && p[1] == 3)
+      g_Crc_Algo = Z7_CRC_NUM_TABLES_USE;
+    else if (p[0] != 1 || p[1] != 2)
+      g_Crc_Algo = 1;
+    else
+#endif // MY_CPU_BE
+    {
+      for (i = 256 * Z7_CRC_NUM_TABLES_TOTAL - 1; i >= 256; i--)
+      {
+        const UInt32 x = g_CrcTable[(size_t)i - 256];
+        g_CrcTable[i] = Z7_BSWAP32(x);
+      }
+#if defined(Z7_CRC_UPDATE_T1_FUNC_NAME)
+      g_Crc_Algo = Z7_CRC_NUM_TABLES_USE;
+#endif
+#if (!defined(MY_CPU_LE) && !defined(MY_CPU_BE))
+      g_Crc_Be = 1;
+#endif
+    }
+  }
+#endif  // !defined(MY_CPU_LE)
+
+#ifdef MY_CPU_LE
+#ifdef Z7_CRC_HW_USE
+  if (CPU_IsSupported_CRC32())
+    g_Crc_Algo = 0;
+#endif // Z7_CRC_HW_USE
+#endif // MY_CPU_LE
+
+#endif // Z7_CRC_NUM_TABLES_USE <= 1
+#endif // g_Crc_Algo was declared
+}
+
+Z7_CRC_UPDATE_FUNC z7_GetFunc_CrcUpdate(unsigned algo)
+{
+  if (algo == 0)
+    return &CrcUpdate;
+
+#if defined(Z7_CRC_HW_USE)
+  if (algo == sizeof(CRC_HW_WORD_TYPE) * 8)
+  {
+#ifdef Z7_CRC_HW_FORCE
+    return &CrcUpdate;
+#else
+    if (g_Crc_Algo == 0)
+      return &CrcUpdate_HW;
+#endif
+  }
+#endif
+
+#ifndef Z7_CRC_HW_FORCE
+  if (algo == Z7_CRC_NUM_TABLES_USE)
+    return
+  #ifdef Z7_CRC_HW_USE
+      &CrcUpdate_Base;
+  #else
+      &CrcUpdate;
+  #endif
+#endif
+
+  return NULL;
+}
+
+#undef kCrcPoly
+#undef Z7_CRC_NUM_TABLES_USE
+#undef Z7_CRC_NUM_TABLES_TOTAL
+#undef CRC_UPDATE_BYTE_2
+#undef FUNC_NAME_LE_2
+#undef FUNC_NAME_LE_1
+#undef FUNC_NAME_LE
+#undef FUNC_NAME_BE_2
+#undef FUNC_NAME_BE_1
+#undef FUNC_NAME_BE
+
+#undef CRC_HW_UNROLL_BYTES
+#undef CRC_HW_WORD_FUNC
+#undef CRC_HW_WORD_TYPE

+ 28 - 0
Components/Lzma2/7zCrc.h

@@ -0,0 +1,28 @@
+/* 7zCrc.h -- CRC32 calculation
+2024-01-22 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_7Z_CRC_H
+#define ZIP7_INC_7Z_CRC_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+extern UInt32 g_CrcTable[];
+
+/* Call CrcGenerateTable one time before other CRC functions */
+void Z7_FASTCALL CrcGenerateTable(void);
+
+#define CRC_INIT_VAL 0xFFFFFFFF
+#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL)
+#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt32 Z7_FASTCALL CrcUpdate(UInt32 crc, const void *data, size_t size);
+UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size);
+
+typedef UInt32 (Z7_FASTCALL *Z7_CRC_UPDATE_FUNC)(UInt32 v, const void *data, size_t size);
+Z7_CRC_UPDATE_FUNC z7_GetFunc_CrcUpdate(unsigned algo);
+
+EXTERN_C_END
+
+#endif

+ 199 - 0
Components/Lzma2/7zCrcOpt.c

@@ -0,0 +1,199 @@
+/* 7zCrcOpt.c -- CRC32 calculation (optimized functions)
+2023-12-07 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "CpuArch.h"
+
+#if !defined(Z7_CRC_NUM_TABLES) || Z7_CRC_NUM_TABLES > 1
+
+// for debug only : define Z7_CRC_DEBUG_BE to test big-endian code in little-endian cpu
+// #define Z7_CRC_DEBUG_BE
+#ifdef Z7_CRC_DEBUG_BE
+#undef MY_CPU_LE
+#define MY_CPU_BE
+#endif
+
+// the value Z7_CRC_NUM_TABLES_USE must be defined to same value as in 7zCrc.c
+#ifdef Z7_CRC_NUM_TABLES
+#define Z7_CRC_NUM_TABLES_USE  Z7_CRC_NUM_TABLES
+#else
+#define Z7_CRC_NUM_TABLES_USE  12
+#endif
+
+#if Z7_CRC_NUM_TABLES_USE % 4     || \
+    Z7_CRC_NUM_TABLES_USE < 4 * 1 || \
+    Z7_CRC_NUM_TABLES_USE > 4 * 6
+  #error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES
+#endif
+
+
+#ifndef MY_CPU_BE
+
+#define CRC_UPDATE_BYTE_2(crc, b)  (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+#define Q(n, d) \
+    ( (table + ((n) * 4 + 3) * 0x100)[(Byte)(d)] \
+    ^ (table + ((n) * 4 + 2) * 0x100)[((d) >> 1 * 8) & 0xFF] \
+    ^ (table + ((n) * 4 + 1) * 0x100)[((d) >> 2 * 8) & 0xFF] \
+    ^ (table + ((n) * 4 + 0) * 0x100)[((d) >> 3 * 8)] )
+
+#define R(a)  *((const UInt32 *)(const void *)p + (a))
+
+#define CRC_FUNC_PRE_LE2(step) \
+UInt32 Z7_FASTCALL CrcUpdateT ## step (UInt32 v, const void *data, size_t size, const UInt32 *table)
+
+#define CRC_FUNC_PRE_LE(step)   \
+        CRC_FUNC_PRE_LE2(step); \
+        CRC_FUNC_PRE_LE2(step)
+
+CRC_FUNC_PRE_LE(Z7_CRC_NUM_TABLES_USE)
+{
+  const Byte *p = (const Byte *)data;
+  const Byte *lim;
+  for (; size && ((unsigned)(ptrdiff_t)p & (7 - (Z7_CRC_NUM_TABLES_USE & 4))) != 0; size--, p++)
+    v = CRC_UPDATE_BYTE_2(v, *p);
+  lim = p + size;
+  if (size >= Z7_CRC_NUM_TABLES_USE)
+  {
+    lim -= Z7_CRC_NUM_TABLES_USE;
+    do
+    {
+      v ^= R(0);
+      {
+#if Z7_CRC_NUM_TABLES_USE == 1 * 4
+        v = Q(0, v);
+#else
+#define U2(r, op) \
+        { d = R(r);  x op Q(Z7_CRC_NUM_TABLES_USE / 4 - 1 - (r), d); }
+        UInt32 d, x;
+        U2(1, =)
+#if Z7_CRC_NUM_TABLES_USE >= 3 * 4
+#define U(r)  U2(r, ^=)
+        U(2)
+#if Z7_CRC_NUM_TABLES_USE >= 4 * 4
+        U(3)
+#if Z7_CRC_NUM_TABLES_USE >= 5 * 4
+        U(4)
+#if Z7_CRC_NUM_TABLES_USE >= 6 * 4
+        U(5)
+#if Z7_CRC_NUM_TABLES_USE >= 7 * 4
+#error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES
+#endif
+#endif
+#endif
+#endif
+#endif
+#undef U
+#undef U2
+        v = x ^ Q(Z7_CRC_NUM_TABLES_USE / 4 - 1, v);
+#endif
+      }
+      p += Z7_CRC_NUM_TABLES_USE;
+    }
+    while (p <= lim);
+    lim += Z7_CRC_NUM_TABLES_USE;
+  }
+  for (; p < lim; p++)
+    v = CRC_UPDATE_BYTE_2(v, *p);
+  return v;
+}
+
+#undef CRC_UPDATE_BYTE_2
+#undef R
+#undef Q
+#undef CRC_FUNC_PRE_LE
+#undef CRC_FUNC_PRE_LE2
+
+#endif
+
+
+
+
+#ifndef MY_CPU_LE
+
+#define CRC_UPDATE_BYTE_2_BE(crc, b)  (table[((crc) >> 24) ^ (b)] ^ ((crc) << 8))
+
+#define Q(n, d) \
+    ( (table + ((n) * 4 + 0) * 0x100)[((d)) & 0xFF] \
+    ^ (table + ((n) * 4 + 1) * 0x100)[((d) >> 1 * 8) & 0xFF] \
+    ^ (table + ((n) * 4 + 2) * 0x100)[((d) >> 2 * 8) & 0xFF] \
+    ^ (table + ((n) * 4 + 3) * 0x100)[((d) >> 3 * 8)] )
+
+#ifdef Z7_CRC_DEBUG_BE
+  #define R(a)  GetBe32a((const UInt32 *)(const void *)p + (a))
+#else
+  #define R(a)         *((const UInt32 *)(const void *)p + (a))
+#endif
+
+
+#define CRC_FUNC_PRE_BE2(step) \
+UInt32 Z7_FASTCALL CrcUpdateT1_BeT ## step (UInt32 v, const void *data, size_t size, const UInt32 *table)
+
+#define CRC_FUNC_PRE_BE(step)   \
+        CRC_FUNC_PRE_BE2(step); \
+        CRC_FUNC_PRE_BE2(step)
+
+CRC_FUNC_PRE_BE(Z7_CRC_NUM_TABLES_USE)
+{
+  const Byte *p = (const Byte *)data;
+  const Byte *lim;
+  table += 0x100;
+  v = Z7_BSWAP32(v);
+  for (; size && ((unsigned)(ptrdiff_t)p & (7 - (Z7_CRC_NUM_TABLES_USE & 4))) != 0; size--, p++)
+    v = CRC_UPDATE_BYTE_2_BE(v, *p);
+  lim = p + size;
+  if (size >= Z7_CRC_NUM_TABLES_USE)
+  {
+    lim -= Z7_CRC_NUM_TABLES_USE;
+    do
+    {
+      v ^= R(0);
+      {
+#if Z7_CRC_NUM_TABLES_USE == 1 * 4
+        v = Q(0, v);
+#else
+#define U2(r, op) \
+        { d = R(r);  x op Q(Z7_CRC_NUM_TABLES_USE / 4 - 1 - (r), d); }
+        UInt32 d, x;
+        U2(1, =)
+#if Z7_CRC_NUM_TABLES_USE >= 3 * 4
+#define U(r)  U2(r, ^=)
+        U(2)
+#if Z7_CRC_NUM_TABLES_USE >= 4 * 4
+        U(3)
+#if Z7_CRC_NUM_TABLES_USE >= 5 * 4
+        U(4)
+#if Z7_CRC_NUM_TABLES_USE >= 6 * 4
+        U(5)
+#if Z7_CRC_NUM_TABLES_USE >= 7 * 4
+#error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES
+#endif
+#endif
+#endif
+#endif
+#endif
+#undef U
+#undef U2
+        v = x ^ Q(Z7_CRC_NUM_TABLES_USE / 4 - 1, v);
+#endif
+      }
+      p += Z7_CRC_NUM_TABLES_USE;
+    }
+    while (p <= lim);
+    lim += Z7_CRC_NUM_TABLES_USE;
+  }
+  for (; p < lim; p++)
+    v = CRC_UPDATE_BYTE_2_BE(v, *p);
+  return Z7_BSWAP32(v);
+}
+
+#undef CRC_UPDATE_BYTE_2_BE
+#undef R
+#undef Q
+#undef CRC_FUNC_PRE_BE
+#undef CRC_FUNC_PRE_BE2
+
+#endif
+#undef Z7_CRC_NUM_TABLES_USE
+#endif

+ 672 - 0
Components/Lzma2/7zDec.c

@@ -0,0 +1,672 @@
+/* 7zDec.c -- Decoding from 7z folder
+2024-03-01 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+/* #define Z7_PPMD_SUPPORT */
+
+#include "7z.h"
+#include "7zCrc.h"
+
+#include "Bcj2.h"
+#include "Bra.h"
+#include "CpuArch.h"
+#include "Delta.h"
+#include "LzmaDec.h"
+#include "Lzma2Dec.h"
+#ifdef Z7_PPMD_SUPPORT
+#include "Ppmd7.h"
+#endif
+
+#define k_Copy 0
+#ifndef Z7_NO_METHOD_LZMA2
+#define k_LZMA2 0x21
+#endif
+#define k_LZMA  0x30101
+#define k_BCJ2  0x303011B
+
+#if !defined(Z7_NO_METHODS_FILTERS)
+#define Z7_USE_BRANCH_FILTER
+#endif
+
+#if !defined(Z7_NO_METHODS_FILTERS) || \
+     defined(Z7_USE_NATIVE_BRANCH_FILTER) && defined(MY_CPU_ARM64)
+#define Z7_USE_FILTER_ARM64
+#ifndef Z7_USE_BRANCH_FILTER
+#define Z7_USE_BRANCH_FILTER
+#endif
+#define k_ARM64 0xa
+#endif
+
+#if !defined(Z7_NO_METHODS_FILTERS) || \
+     defined(Z7_USE_NATIVE_BRANCH_FILTER) && defined(MY_CPU_ARMT)
+#define Z7_USE_FILTER_ARMT
+#ifndef Z7_USE_BRANCH_FILTER
+#define Z7_USE_BRANCH_FILTER
+#endif
+#define k_ARMT  0x3030701
+#endif
+
+#ifndef Z7_NO_METHODS_FILTERS
+#define k_Delta 3
+#define k_RISCV 0xb
+#define k_BCJ   0x3030103
+#define k_PPC   0x3030205
+#define k_IA64  0x3030401
+#define k_ARM   0x3030501
+#define k_SPARC 0x3030805
+#endif
+
+#ifdef Z7_PPMD_SUPPORT
+
+#define k_PPMD 0x30401
+
+typedef struct
+{
+  IByteIn vt;
+  const Byte *cur;
+  const Byte *end;
+  const Byte *begin;
+  UInt64 processed;
+  BoolInt extra;
+  SRes res;
+  ILookInStreamPtr inStream;
+} CByteInToLook;
+
+static Byte ReadByte(IByteInPtr pp)
+{
+  Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CByteInToLook)
+  if (p->cur != p->end)
+    return *p->cur++;
+  if (p->res == SZ_OK)
+  {
+    size_t size = (size_t)(p->cur - p->begin);
+    p->processed += size;
+    p->res = ILookInStream_Skip(p->inStream, size);
+    size = (1 << 25);
+    p->res = ILookInStream_Look(p->inStream, (const void **)&p->begin, &size);
+    p->cur = p->begin;
+    p->end = p->begin + size;
+    if (size != 0)
+      return *p->cur++;
+  }
+  p->extra = True;
+  return 0;
+}
+
+static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
+    Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
+{
+  CPpmd7 ppmd;
+  CByteInToLook s;
+  SRes res = SZ_OK;
+
+  s.vt.Read = ReadByte;
+  s.inStream = inStream;
+  s.begin = s.end = s.cur = NULL;
+  s.extra = False;
+  s.res = SZ_OK;
+  s.processed = 0;
+
+  if (propsSize != 5)
+    return SZ_ERROR_UNSUPPORTED;
+
+  {
+    unsigned order = props[0];
+    UInt32 memSize = GetUi32(props + 1);
+    if (order < PPMD7_MIN_ORDER ||
+        order > PPMD7_MAX_ORDER ||
+        memSize < PPMD7_MIN_MEM_SIZE ||
+        memSize > PPMD7_MAX_MEM_SIZE)
+      return SZ_ERROR_UNSUPPORTED;
+    Ppmd7_Construct(&ppmd);
+    if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
+      return SZ_ERROR_MEM;
+    Ppmd7_Init(&ppmd, order);
+  }
+  {
+    ppmd.rc.dec.Stream = &s.vt;
+    if (!Ppmd7z_RangeDec_Init(&ppmd.rc.dec))
+      res = SZ_ERROR_DATA;
+    else if (!s.extra)
+    {
+      Byte *buf = outBuffer;
+      const Byte *lim = buf + outSize;
+      for (; buf != lim; buf++)
+      {
+        int sym = Ppmd7z_DecodeSymbol(&ppmd);
+        if (s.extra || sym < 0)
+          break;
+        *buf = (Byte)sym;
+      }
+      if (buf != lim)
+        res = SZ_ERROR_DATA;
+      else if (!Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec))
+      {
+        /* if (Ppmd7z_DecodeSymbol(&ppmd) != PPMD7_SYM_END || !Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) */
+        res = SZ_ERROR_DATA;
+      }
+    }
+    if (s.extra)
+      res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
+    else if (s.processed + (size_t)(s.cur - s.begin) != inSize)
+      res = SZ_ERROR_DATA;
+  }
+  Ppmd7_Free(&ppmd, allocMain);
+  return res;
+}
+
+#endif
+
+
+static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
+    Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
+{
+  CLzmaDec state;
+  SRes res = SZ_OK;
+
+  LzmaDec_CONSTRUCT(&state)
+  RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain))
+  state.dic = outBuffer;
+  state.dicBufSize = outSize;
+  LzmaDec_Init(&state);
+
+  for (;;)
+  {
+    const void *inBuf = NULL;
+    size_t lookahead = (1 << 18);
+    if (lookahead > inSize)
+      lookahead = (size_t)inSize;
+    res = ILookInStream_Look(inStream, &inBuf, &lookahead);
+    if (res != SZ_OK)
+      break;
+
+    {
+      SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
+      ELzmaStatus status;
+      res = LzmaDec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
+      lookahead -= inProcessed;
+      inSize -= inProcessed;
+      if (res != SZ_OK)
+        break;
+
+      if (status == LZMA_STATUS_FINISHED_WITH_MARK)
+      {
+        if (outSize != state.dicPos || inSize != 0)
+          res = SZ_ERROR_DATA;
+        break;
+      }
+
+      if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
+        break;
+
+      if (inProcessed == 0 && dicPos == state.dicPos)
+      {
+        res = SZ_ERROR_DATA;
+        break;
+      }
+
+      res = ILookInStream_Skip(inStream, inProcessed);
+      if (res != SZ_OK)
+        break;
+    }
+  }
+
+  LzmaDec_FreeProbs(&state, allocMain);
+  return res;
+}
+
+
+#ifndef Z7_NO_METHOD_LZMA2
+
+static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
+    Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
+{
+  CLzma2Dec state;
+  SRes res = SZ_OK;
+
+  Lzma2Dec_CONSTRUCT(&state)
+  if (propsSize != 1)
+    return SZ_ERROR_DATA;
+  RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain))
+  state.decoder.dic = outBuffer;
+  state.decoder.dicBufSize = outSize;
+  Lzma2Dec_Init(&state);
+
+  for (;;)
+  {
+    const void *inBuf = NULL;
+    size_t lookahead = (1 << 18);
+    if (lookahead > inSize)
+      lookahead = (size_t)inSize;
+    res = ILookInStream_Look(inStream, &inBuf, &lookahead);
+    if (res != SZ_OK)
+      break;
+
+    {
+      SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
+      ELzmaStatus status;
+      res = Lzma2Dec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
+      lookahead -= inProcessed;
+      inSize -= inProcessed;
+      if (res != SZ_OK)
+        break;
+
+      if (status == LZMA_STATUS_FINISHED_WITH_MARK)
+      {
+        if (outSize != state.decoder.dicPos || inSize != 0)
+          res = SZ_ERROR_DATA;
+        break;
+      }
+
+      if (inProcessed == 0 && dicPos == state.decoder.dicPos)
+      {
+        res = SZ_ERROR_DATA;
+        break;
+      }
+
+      res = ILookInStream_Skip(inStream, inProcessed);
+      if (res != SZ_OK)
+        break;
+    }
+  }
+
+  Lzma2Dec_FreeProbs(&state, allocMain);
+  return res;
+}
+
+#endif
+
+
+static SRes SzDecodeCopy(UInt64 inSize, ILookInStreamPtr inStream, Byte *outBuffer)
+{
+  while (inSize > 0)
+  {
+    const void *inBuf;
+    size_t curSize = (1 << 18);
+    if (curSize > inSize)
+      curSize = (size_t)inSize;
+    RINOK(ILookInStream_Look(inStream, &inBuf, &curSize))
+    if (curSize == 0)
+      return SZ_ERROR_INPUT_EOF;
+    memcpy(outBuffer, inBuf, curSize);
+    outBuffer += curSize;
+    inSize -= curSize;
+    RINOK(ILookInStream_Skip(inStream, curSize))
+  }
+  return SZ_OK;
+}
+
+static BoolInt IS_MAIN_METHOD(UInt32 m)
+{
+  switch (m)
+  {
+    case k_Copy:
+    case k_LZMA:
+  #ifndef Z7_NO_METHOD_LZMA2
+    case k_LZMA2:
+  #endif
+  #ifdef Z7_PPMD_SUPPORT
+    case k_PPMD:
+  #endif
+      return True;
+  }
+  return False;
+}
+
+static BoolInt IS_SUPPORTED_CODER(const CSzCoderInfo *c)
+{
+  return
+      c->NumStreams == 1
+      /* && c->MethodID <= (UInt32)0xFFFFFFFF */
+      && IS_MAIN_METHOD((UInt32)c->MethodID);
+}
+
+#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4)
+
+static SRes CheckSupportedFolder(const CSzFolder *f)
+{
+  if (f->NumCoders < 1 || f->NumCoders > 4)
+    return SZ_ERROR_UNSUPPORTED;
+  if (!IS_SUPPORTED_CODER(&f->Coders[0]))
+    return SZ_ERROR_UNSUPPORTED;
+  if (f->NumCoders == 1)
+  {
+    if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0)
+      return SZ_ERROR_UNSUPPORTED;
+    return SZ_OK;
+  }
+  
+  
+  #if defined(Z7_USE_BRANCH_FILTER)
+
+  if (f->NumCoders == 2)
+  {
+    const CSzCoderInfo *c = &f->Coders[1];
+    if (
+        /* c->MethodID > (UInt32)0xFFFFFFFF || */
+        c->NumStreams != 1
+        || f->NumPackStreams != 1
+        || f->PackStreams[0] != 0
+        || f->NumBonds != 1
+        || f->Bonds[0].InIndex != 1
+        || f->Bonds[0].OutIndex != 0)
+      return SZ_ERROR_UNSUPPORTED;
+    switch ((UInt32)c->MethodID)
+    {
+    #if !defined(Z7_NO_METHODS_FILTERS)
+      case k_Delta:
+      case k_BCJ:
+      case k_PPC:
+      case k_IA64:
+      case k_SPARC:
+      case k_ARM:
+      case k_RISCV:
+    #endif
+    #ifdef Z7_USE_FILTER_ARM64
+      case k_ARM64:
+    #endif
+    #ifdef Z7_USE_FILTER_ARMT
+      case k_ARMT:
+    #endif
+        break;
+      default:
+        return SZ_ERROR_UNSUPPORTED;
+    }
+    return SZ_OK;
+  }
+
+  #endif
+
+  
+  if (f->NumCoders == 4)
+  {
+    if (!IS_SUPPORTED_CODER(&f->Coders[1])
+        || !IS_SUPPORTED_CODER(&f->Coders[2])
+        || !IS_BCJ2(&f->Coders[3]))
+      return SZ_ERROR_UNSUPPORTED;
+    if (f->NumPackStreams != 4
+        || f->PackStreams[0] != 2
+        || f->PackStreams[1] != 6
+        || f->PackStreams[2] != 1
+        || f->PackStreams[3] != 0
+        || f->NumBonds != 3
+        || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0
+        || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1
+        || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2)
+      return SZ_ERROR_UNSUPPORTED;
+    return SZ_OK;
+  }
+  
+  return SZ_ERROR_UNSUPPORTED;
+}
+
+
+
+
+
+
+static SRes SzFolder_Decode2(const CSzFolder *folder,
+    const Byte *propsData,
+    const UInt64 *unpackSizes,
+    const UInt64 *packPositions,
+    ILookInStreamPtr inStream, UInt64 startPos,
+    Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain,
+    Byte *tempBuf[])
+{
+  UInt32 ci;
+  SizeT tempSizes[3] = { 0, 0, 0};
+  SizeT tempSize3 = 0;
+  Byte *tempBuf3 = 0;
+
+  RINOK(CheckSupportedFolder(folder))
+
+  for (ci = 0; ci < folder->NumCoders; ci++)
+  {
+    const CSzCoderInfo *coder = &folder->Coders[ci];
+
+    if (IS_MAIN_METHOD((UInt32)coder->MethodID))
+    {
+      UInt32 si = 0;
+      UInt64 offset;
+      UInt64 inSize;
+      Byte *outBufCur = outBuffer;
+      SizeT outSizeCur = outSize;
+      if (folder->NumCoders == 4)
+      {
+        const UInt32 indices[] = { 3, 2, 0 };
+        const UInt64 unpackSize = unpackSizes[ci];
+        si = indices[ci];
+        if (ci < 2)
+        {
+          Byte *temp;
+          outSizeCur = (SizeT)unpackSize;
+          if (outSizeCur != unpackSize)
+            return SZ_ERROR_MEM;
+          temp = (Byte *)ISzAlloc_Alloc(allocMain, outSizeCur);
+          if (!temp && outSizeCur != 0)
+            return SZ_ERROR_MEM;
+          outBufCur = tempBuf[1 - ci] = temp;
+          tempSizes[1 - ci] = outSizeCur;
+        }
+        else if (ci == 2)
+        {
+          if (unpackSize > outSize) /* check it */
+            return SZ_ERROR_PARAM;
+          tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
+          tempSize3 = outSizeCur = (SizeT)unpackSize;
+        }
+        else
+          return SZ_ERROR_UNSUPPORTED;
+      }
+      offset = packPositions[si];
+      inSize = packPositions[(size_t)si + 1] - offset;
+      RINOK(LookInStream_SeekTo(inStream, startPos + offset))
+
+      if (coder->MethodID == k_Copy)
+      {
+        if (inSize != outSizeCur) /* check it */
+          return SZ_ERROR_DATA;
+        RINOK(SzDecodeCopy(inSize, inStream, outBufCur))
+      }
+      else if (coder->MethodID == k_LZMA)
+      {
+        RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain))
+      }
+    #ifndef Z7_NO_METHOD_LZMA2
+      else if (coder->MethodID == k_LZMA2)
+      {
+        RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain))
+      }
+    #endif
+    #ifdef Z7_PPMD_SUPPORT
+      else if (coder->MethodID == k_PPMD)
+      {
+        RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain))
+      }
+    #endif
+      else
+        return SZ_ERROR_UNSUPPORTED;
+    }
+    else if (coder->MethodID == k_BCJ2)
+    {
+      const UInt64 offset = packPositions[1];
+      const UInt64 s3Size = packPositions[2] - offset;
+      
+      if (ci != 3)
+        return SZ_ERROR_UNSUPPORTED;
+      
+      tempSizes[2] = (SizeT)s3Size;
+      if (tempSizes[2] != s3Size)
+        return SZ_ERROR_MEM;
+      tempBuf[2] = (Byte *)ISzAlloc_Alloc(allocMain, tempSizes[2]);
+      if (!tempBuf[2] && tempSizes[2] != 0)
+        return SZ_ERROR_MEM;
+      
+      RINOK(LookInStream_SeekTo(inStream, startPos + offset))
+      RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2]))
+
+      if ((tempSizes[0] & 3) != 0 ||
+          (tempSizes[1] & 3) != 0 ||
+          tempSize3 + tempSizes[0] + tempSizes[1] != outSize)
+        return SZ_ERROR_DATA;
+
+      {
+        CBcj2Dec p;
+        
+        p.bufs[0] = tempBuf3;   p.lims[0] = tempBuf3 + tempSize3;
+        p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0];
+        p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1];
+        p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2];
+        
+        p.dest = outBuffer;
+        p.destLim = outBuffer + outSize;
+        
+        Bcj2Dec_Init(&p);
+        RINOK(Bcj2Dec_Decode(&p))
+
+        {
+          unsigned i;
+          for (i = 0; i < 4; i++)
+            if (p.bufs[i] != p.lims[i])
+              return SZ_ERROR_DATA;
+          if (p.dest != p.destLim || !Bcj2Dec_IsMaybeFinished(&p))
+            return SZ_ERROR_DATA;
+        }
+      }
+    }
+#if defined(Z7_USE_BRANCH_FILTER)
+    else if (ci == 1)
+    {
+#if !defined(Z7_NO_METHODS_FILTERS)
+      if (coder->MethodID == k_Delta)
+      {
+        if (coder->PropsSize != 1)
+          return SZ_ERROR_UNSUPPORTED;
+        {
+          Byte state[DELTA_STATE_SIZE];
+          Delta_Init(state);
+          Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize);
+        }
+        continue;
+      }
+#endif
+     
+#ifdef Z7_USE_FILTER_ARM64
+      if (coder->MethodID == k_ARM64)
+      {
+        UInt32 pc = 0;
+        if (coder->PropsSize == 4)
+        {
+          pc = GetUi32(propsData + coder->PropsOffset);
+          if (pc & 3)
+            return SZ_ERROR_UNSUPPORTED;
+        }
+        else if (coder->PropsSize != 0)
+          return SZ_ERROR_UNSUPPORTED;
+        z7_BranchConv_ARM64_Dec(outBuffer, outSize, pc);
+        continue;
+      }
+#endif
+
+#if !defined(Z7_NO_METHODS_FILTERS)
+      if (coder->MethodID == k_RISCV)
+      {
+        UInt32 pc = 0;
+        if (coder->PropsSize == 4)
+        {
+          pc = GetUi32(propsData + coder->PropsOffset);
+          if (pc & 1)
+            return SZ_ERROR_UNSUPPORTED;
+        }
+        else if (coder->PropsSize != 0)
+          return SZ_ERROR_UNSUPPORTED;
+        z7_BranchConv_RISCV_Dec(outBuffer, outSize, pc);
+        continue;
+      }
+#endif
+      
+#if !defined(Z7_NO_METHODS_FILTERS) || defined(Z7_USE_FILTER_ARMT)
+      {
+        if (coder->PropsSize != 0)
+          return SZ_ERROR_UNSUPPORTED;
+       #define CASE_BRA_CONV(isa) case k_ ## isa: Z7_BRANCH_CONV_DEC(isa)(outBuffer, outSize, 0); break; // pc = 0;
+        switch (coder->MethodID)
+        {
+         #if !defined(Z7_NO_METHODS_FILTERS)
+          case k_BCJ:
+          {
+            UInt32 state = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL;
+            z7_BranchConvSt_X86_Dec(outBuffer, outSize, 0, &state); // pc = 0
+            break;
+          }
+          case k_PPC: Z7_BRANCH_CONV_DEC_2(BranchConv_PPC)(outBuffer, outSize, 0); break; // pc = 0;
+          // CASE_BRA_CONV(PPC)
+          CASE_BRA_CONV(IA64)
+          CASE_BRA_CONV(SPARC)
+          CASE_BRA_CONV(ARM)
+         #endif
+         #if !defined(Z7_NO_METHODS_FILTERS) || defined(Z7_USE_FILTER_ARMT)
+          CASE_BRA_CONV(ARMT)
+         #endif
+          default:
+            return SZ_ERROR_UNSUPPORTED;
+        }
+        continue;
+      }
+#endif
+    } // (c == 1)
+#endif // Z7_USE_BRANCH_FILTER
+    else
+      return SZ_ERROR_UNSUPPORTED;
+  }
+
+  return SZ_OK;
+}
+
+
+SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
+    ILookInStreamPtr inStream, UInt64 startPos,
+    Byte *outBuffer, size_t outSize,
+    ISzAllocPtr allocMain)
+{
+  SRes res;
+  CSzFolder folder;
+  CSzData sd;
+  
+  const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex];
+  sd.Data = data;
+  sd.Size = p->FoCodersOffsets[(size_t)folderIndex + 1] - p->FoCodersOffsets[folderIndex];
+  
+  res = SzGetNextFolderItem(&folder, &sd);
+  
+  if (res != SZ_OK)
+    return res;
+
+  if (sd.Size != 0
+      || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex]
+      || outSize != SzAr_GetFolderUnpackSize(p, folderIndex))
+    return SZ_ERROR_FAIL;
+  {
+    unsigned i;
+    Byte *tempBuf[3] = { 0, 0, 0};
+
+    res = SzFolder_Decode2(&folder, data,
+        &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]],
+        p->PackPositions + p->FoStartPackStreamIndex[folderIndex],
+        inStream, startPos,
+        outBuffer, (SizeT)outSize, allocMain, tempBuf);
+    
+    for (i = 0; i < 3; i++)
+      ISzAlloc_Free(allocMain, tempBuf[i]);
+
+    if (res == SZ_OK)
+      if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex))
+        if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex])
+          res = SZ_ERROR_CRC;
+
+    return res;
+  }
+}

+ 443 - 0
Components/Lzma2/7zFile.c

@@ -0,0 +1,443 @@
+/* 7zFile.c -- File IO
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "7zFile.h"
+
+#ifndef USE_WINDOWS_FILE
+
+  #include <errno.h>
+
+  #ifndef USE_FOPEN
+    #include <stdio.h>
+    #include <fcntl.h>
+    #ifdef _WIN32
+      #include <io.h>
+      typedef int ssize_t;
+      typedef int off_t;
+    #else
+      #include <unistd.h>
+    #endif
+  #endif
+
+#else
+
+/*
+   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).
+   Probably in some version of Windows there are problems with other sizes:
+   for 32 MB (maybe also for 16 MB).
+   And message can be "Network connection was lost"
+*/
+
+#endif
+
+#define kChunkSizeMax (1 << 22)
+
+void File_Construct(CSzFile *p)
+{
+  #ifdef USE_WINDOWS_FILE
+  p->handle = INVALID_HANDLE_VALUE;
+  #elif defined(USE_FOPEN)
+  p->file = NULL;
+  #else
+  p->fd = -1;
+  #endif
+}
+
+#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
+
+static WRes File_Open(CSzFile *p, const char *name, int writeMode)
+{
+  #ifdef USE_WINDOWS_FILE
+  
+  p->handle = CreateFileA(name,
+      writeMode ? GENERIC_WRITE : GENERIC_READ,
+      FILE_SHARE_READ, NULL,
+      writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
+      FILE_ATTRIBUTE_NORMAL, NULL);
+  return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
+  
+  #elif defined(USE_FOPEN)
+  
+  p->file = fopen(name, writeMode ? "wb+" : "rb");
+  return (p->file != 0) ? 0 :
+    #ifdef UNDER_CE
+    2; /* ENOENT */
+    #else
+    errno;
+    #endif
+  
+  #else
+
+  int flags = (writeMode ? (O_CREAT | O_EXCL | O_WRONLY) : O_RDONLY);
+  #ifdef O_BINARY
+  flags |= O_BINARY;
+  #endif
+  p->fd = open(name, flags, 0666);
+  return (p->fd != -1) ? 0 : errno;
+
+  #endif
+}
+
+WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); }
+
+WRes OutFile_Open(CSzFile *p, const char *name)
+{
+  #if defined(USE_WINDOWS_FILE) || defined(USE_FOPEN)
+  return File_Open(p, name, 1);
+  #else
+  p->fd = creat(name, 0666);
+  return (p->fd != -1) ? 0 : errno;
+  #endif
+}
+
+#endif
+
+
+#ifdef USE_WINDOWS_FILE
+static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode)
+{
+  p->handle = CreateFileW(name,
+      writeMode ? GENERIC_WRITE : GENERIC_READ,
+      FILE_SHARE_READ, NULL,
+      writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
+      FILE_ATTRIBUTE_NORMAL, NULL);
+  return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
+}
+WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); }
+WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); }
+#endif
+
+WRes File_Close(CSzFile *p)
+{
+  #ifdef USE_WINDOWS_FILE
+  
+  if (p->handle != INVALID_HANDLE_VALUE)
+  {
+    if (!CloseHandle(p->handle))
+      return GetLastError();
+    p->handle = INVALID_HANDLE_VALUE;
+  }
+  
+  #elif defined(USE_FOPEN)
+
+  if (p->file != NULL)
+  {
+    int res = fclose(p->file);
+    if (res != 0)
+    {
+      if (res == EOF)
+        return errno;
+      return res;
+    }
+    p->file = NULL;
+  }
+
+  #else
+
+  if (p->fd != -1)
+  {
+    if (close(p->fd) != 0)
+      return errno;
+    p->fd = -1;
+  }
+
+  #endif
+
+  return 0;
+}
+
+
+WRes File_Read(CSzFile *p, void *data, size_t *size)
+{
+  size_t originalSize = *size;
+  *size = 0;
+  if (originalSize == 0)
+    return 0;
+
+  #ifdef USE_WINDOWS_FILE
+
+  do
+  {
+    const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
+    DWORD processed = 0;
+    const BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL);
+    data = (void *)((Byte *)data + processed);
+    originalSize -= processed;
+    *size += processed;
+    if (!res)
+      return GetLastError();
+    // debug : we can break here for partial reading mode
+    if (processed == 0)
+      break;
+  }
+  while (originalSize > 0);
+
+  #elif defined(USE_FOPEN)
+
+  do
+  {
+    const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
+    const size_t processed = fread(data, 1, curSize, p->file);
+    data = (void *)((Byte *)data + (size_t)processed);
+    originalSize -= processed;
+    *size += processed;
+    if (processed != curSize)
+      return ferror(p->file);
+    // debug : we can break here for partial reading mode
+    if (processed == 0)
+      break;
+  }
+  while (originalSize > 0);
+
+  #else
+
+  do
+  {
+    const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
+    const ssize_t processed = read(p->fd, data, curSize);
+    if (processed == -1)
+      return errno;
+    if (processed == 0)
+      break;
+    data = (void *)((Byte *)data + (size_t)processed);
+    originalSize -= (size_t)processed;
+    *size += (size_t)processed;
+    // debug : we can break here for partial reading mode
+    // break;
+  }
+  while (originalSize > 0);
+
+  #endif
+
+  return 0;
+}
+
+
+WRes File_Write(CSzFile *p, const void *data, size_t *size)
+{
+  size_t originalSize = *size;
+  *size = 0;
+  if (originalSize == 0)
+    return 0;
+  
+  #ifdef USE_WINDOWS_FILE
+
+  do
+  {
+    const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
+    DWORD processed = 0;
+    const BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL);
+    data = (const void *)((const Byte *)data + processed);
+    originalSize -= processed;
+    *size += processed;
+    if (!res)
+      return GetLastError();
+    if (processed == 0)
+      break;
+  }
+  while (originalSize > 0);
+
+  #elif defined(USE_FOPEN)
+
+  do
+  {
+    const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
+    const size_t processed = fwrite(data, 1, curSize, p->file);
+    data = (void *)((Byte *)data + (size_t)processed);
+    originalSize -= processed;
+    *size += processed;
+    if (processed != curSize)
+      return ferror(p->file);
+    if (processed == 0)
+      break;
+  }
+  while (originalSize > 0);
+
+  #else
+
+  do
+  {
+    const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
+    const ssize_t processed = write(p->fd, data, curSize);
+    if (processed == -1)
+      return errno;
+    if (processed == 0)
+      break;
+    data = (const void *)((const Byte *)data + (size_t)processed);
+    originalSize -= (size_t)processed;
+    *size += (size_t)processed;
+  }
+  while (originalSize > 0);
+
+  #endif
+
+  return 0;
+}
+
+
+WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin)
+{
+  #ifdef USE_WINDOWS_FILE
+
+  DWORD moveMethod;
+  UInt32 low = (UInt32)*pos;
+  LONG high = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */
+  // (int) to eliminate clang warning
+  switch ((int)origin)
+  {
+    case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break;
+    case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break;
+    case SZ_SEEK_END: moveMethod = FILE_END; break;
+    default: return ERROR_INVALID_PARAMETER;
+  }
+  low = SetFilePointer(p->handle, (LONG)low, &high, moveMethod);
+  if (low == (UInt32)0xFFFFFFFF)
+  {
+    WRes res = GetLastError();
+    if (res != NO_ERROR)
+      return res;
+  }
+  *pos = ((Int64)high << 32) | low;
+  return 0;
+
+  #else
+  
+  int moveMethod; // = origin;
+
+  switch ((int)origin)
+  {
+    case SZ_SEEK_SET: moveMethod = SEEK_SET; break;
+    case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break;
+    case SZ_SEEK_END: moveMethod = SEEK_END; break;
+    default: return EINVAL;
+  }
+  
+  #if defined(USE_FOPEN)
+  {
+    int res = fseek(p->file, (long)*pos, moveMethod);
+    if (res == -1)
+      return errno;
+    *pos = ftell(p->file);
+    if (*pos == -1)
+      return errno;
+    return 0;
+  }
+  #else
+  {
+    off_t res = lseek(p->fd, (off_t)*pos, moveMethod);
+    if (res == -1)
+      return errno;
+    *pos = res;
+    return 0;
+  }
+  
+  #endif // USE_FOPEN
+  #endif // USE_WINDOWS_FILE
+}
+
+
+WRes File_GetLength(CSzFile *p, UInt64 *length)
+{
+  #ifdef USE_WINDOWS_FILE
+  
+  DWORD sizeHigh;
+  DWORD sizeLow = GetFileSize(p->handle, &sizeHigh);
+  if (sizeLow == 0xFFFFFFFF)
+  {
+    DWORD res = GetLastError();
+    if (res != NO_ERROR)
+      return res;
+  }
+  *length = (((UInt64)sizeHigh) << 32) + sizeLow;
+  return 0;
+  
+  #elif defined(USE_FOPEN)
+  
+  long pos = ftell(p->file);
+  int res = fseek(p->file, 0, SEEK_END);
+  *length = ftell(p->file);
+  fseek(p->file, pos, SEEK_SET);
+  return res;
+
+  #else
+
+  off_t pos;
+  *length = 0;
+  pos = lseek(p->fd, 0, SEEK_CUR);
+  if (pos != -1)
+  {
+    const off_t len2 = lseek(p->fd, 0, SEEK_END);
+    const off_t res2 = lseek(p->fd, pos, SEEK_SET);
+    if (len2 != -1)
+    {
+      *length = (UInt64)len2;
+      if (res2 != -1)
+        return 0;
+    }
+  }
+  return errno;
+  
+  #endif
+}
+
+
+/* ---------- FileSeqInStream ---------- */
+
+static SRes FileSeqInStream_Read(ISeqInStreamPtr pp, void *buf, size_t *size)
+{
+  Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileSeqInStream)
+  const WRes wres = File_Read(&p->file, buf, size);
+  p->wres = wres;
+  return (wres == 0) ? SZ_OK : SZ_ERROR_READ;
+}
+
+void FileSeqInStream_CreateVTable(CFileSeqInStream *p)
+{
+  p->vt.Read = FileSeqInStream_Read;
+}
+
+
+/* ---------- FileInStream ---------- */
+
+static SRes FileInStream_Read(ISeekInStreamPtr pp, void *buf, size_t *size)
+{
+  Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileInStream)
+  const WRes wres = File_Read(&p->file, buf, size);
+  p->wres = wres;
+  return (wres == 0) ? SZ_OK : SZ_ERROR_READ;
+}
+
+static SRes FileInStream_Seek(ISeekInStreamPtr pp, Int64 *pos, ESzSeek origin)
+{
+  Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileInStream)
+  const WRes wres = File_Seek(&p->file, pos, origin);
+  p->wres = wres;
+  return (wres == 0) ? SZ_OK : SZ_ERROR_READ;
+}
+
+void FileInStream_CreateVTable(CFileInStream *p)
+{
+  p->vt.Read = FileInStream_Read;
+  p->vt.Seek = FileInStream_Seek;
+}
+
+
+/* ---------- FileOutStream ---------- */
+
+static size_t FileOutStream_Write(ISeqOutStreamPtr pp, const void *data, size_t size)
+{
+  Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileOutStream)
+  const WRes wres = File_Write(&p->file, data, &size);
+  p->wres = wres;
+  return size;
+}
+
+void FileOutStream_CreateVTable(CFileOutStream *p)
+{
+  p->vt.Write = FileOutStream_Write;
+}

+ 92 - 0
Components/Lzma2/7zFile.h

@@ -0,0 +1,92 @@
+/* 7zFile.h -- File IO
+2023-03-05 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_FILE_H
+#define ZIP7_INC_FILE_H
+
+#ifdef _WIN32
+#define USE_WINDOWS_FILE
+// #include <windows.h>
+#endif
+
+#ifdef USE_WINDOWS_FILE
+#include "7zWindows.h"
+
+#else
+// note: USE_FOPEN mode is limited to 32-bit file size
+// #define USE_FOPEN
+// #include <stdio.h>
+#endif
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/* ---------- File ---------- */
+
+typedef struct
+{
+  #ifdef USE_WINDOWS_FILE
+  HANDLE handle;
+  #elif defined(USE_FOPEN)
+  FILE *file;
+  #else
+  int fd;
+  #endif
+} CSzFile;
+
+void File_Construct(CSzFile *p);
+#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
+WRes InFile_Open(CSzFile *p, const char *name);
+WRes OutFile_Open(CSzFile *p, const char *name);
+#endif
+#ifdef USE_WINDOWS_FILE
+WRes InFile_OpenW(CSzFile *p, const WCHAR *name);
+WRes OutFile_OpenW(CSzFile *p, const WCHAR *name);
+#endif
+WRes File_Close(CSzFile *p);
+
+/* reads max(*size, remain file's size) bytes */
+WRes File_Read(CSzFile *p, void *data, size_t *size);
+
+/* writes *size bytes */
+WRes File_Write(CSzFile *p, const void *data, size_t *size);
+
+WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin);
+WRes File_GetLength(CSzFile *p, UInt64 *length);
+
+
+/* ---------- FileInStream ---------- */
+
+typedef struct
+{
+  ISeqInStream vt;
+  CSzFile file;
+  WRes wres;
+} CFileSeqInStream;
+
+void FileSeqInStream_CreateVTable(CFileSeqInStream *p);
+
+
+typedef struct
+{
+  ISeekInStream vt;
+  CSzFile file;
+  WRes wres;
+} CFileInStream;
+
+void FileInStream_CreateVTable(CFileInStream *p);
+
+
+typedef struct
+{
+  ISeqOutStream vt;
+  CSzFile file;
+  WRes wres;
+} CFileOutStream;
+
+void FileOutStream_CreateVTable(CFileOutStream *p);
+
+EXTERN_C_END
+
+#endif

+ 27 - 0
Components/Lzma2/7zVersion.h

@@ -0,0 +1,27 @@
+#define MY_VER_MAJOR 24
+#define MY_VER_MINOR 8
+#define MY_VER_BUILD 0
+#define MY_VERSION_NUMBERS "24.08"
+#define MY_VERSION MY_VERSION_NUMBERS
+
+#ifdef MY_CPU_NAME
+  #define MY_VERSION_CPU MY_VERSION " (" MY_CPU_NAME ")"
+#else
+  #define MY_VERSION_CPU MY_VERSION
+#endif
+
+#define MY_DATE "2024-08-11"
+#undef MY_COPYRIGHT
+#undef MY_VERSION_COPYRIGHT_DATE
+#define MY_AUTHOR_NAME "Igor Pavlov"
+#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain"
+#define MY_COPYRIGHT_CR "Copyright (c) 1999-2024 Igor Pavlov"
+
+#ifdef USE_COPYRIGHT_CR
+  #define MY_COPYRIGHT MY_COPYRIGHT_CR
+#else
+  #define MY_COPYRIGHT MY_COPYRIGHT_PD
+#endif
+
+#define MY_COPYRIGHT_DATE MY_COPYRIGHT " : " MY_DATE
+#define MY_VERSION_COPYRIGHT_DATE MY_VERSION_CPU " : " MY_COPYRIGHT " : " MY_DATE

+ 290 - 0
Components/Lzma2/Bcj2.c

@@ -0,0 +1,290 @@
+/* Bcj2.c -- BCJ2 Decoder (Converter for x86 code)
+2023-03-01 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Bcj2.h"
+#include "CpuArch.h"
+
+#define kTopValue ((UInt32)1 << 24)
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+// UInt32 bcj2_stats[256 + 2][2];
+
+void Bcj2Dec_Init(CBcj2Dec *p)
+{
+  unsigned i;
+  p->state = BCJ2_STREAM_RC; // BCJ2_DEC_STATE_OK;
+  p->ip = 0;
+  p->temp = 0;
+  p->range = 0;
+  p->code = 0;
+  for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++)
+    p->probs[i] = kBitModelTotal >> 1;
+}
+
+SRes Bcj2Dec_Decode(CBcj2Dec *p)
+{
+  UInt32 v = p->temp;
+  // const Byte *src;
+  if (p->range <= 5)
+  {
+    UInt32 code = p->code;
+    p->state = BCJ2_DEC_STATE_ERROR; /* for case if we return SZ_ERROR_DATA; */
+    for (; p->range != 5; p->range++)
+    {
+      if (p->range == 1 && code != 0)
+        return SZ_ERROR_DATA;
+      if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC])
+      {
+        p->state = BCJ2_STREAM_RC;
+        return SZ_OK;
+      }
+      code = (code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
+      p->code = code;
+    }
+    if (code == 0xffffffff)
+      return SZ_ERROR_DATA;
+    p->range = 0xffffffff;
+  }
+  // else
+  {
+    unsigned state = p->state;
+    // we check BCJ2_IS_32BIT_STREAM() here instead of check in the main loop
+    if (BCJ2_IS_32BIT_STREAM(state))
+    {
+      const Byte *cur = p->bufs[state];
+      if (cur == p->lims[state])
+        return SZ_OK;
+      p->bufs[state] = cur + 4;
+      {
+        const UInt32 ip = p->ip + 4;
+        v = GetBe32a(cur) - ip;
+        p->ip = ip;
+      }
+      state = BCJ2_DEC_STATE_ORIG_0;
+    }
+    if ((unsigned)(state - BCJ2_DEC_STATE_ORIG_0) < 4)
+    {
+      Byte *dest = p->dest;
+      for (;;)
+      {
+        if (dest == p->destLim)
+        {
+          p->state = state;
+          p->temp = v;
+          return SZ_OK;
+        }
+        *dest++ = (Byte)v;
+        p->dest = dest;
+        if (++state == BCJ2_DEC_STATE_ORIG_3 + 1)
+          break;
+        v >>= 8;
+      }
+    }
+  }
+
+  // src = p->bufs[BCJ2_STREAM_MAIN];
+  for (;;)
+  {
+    /*
+    if (BCJ2_IS_32BIT_STREAM(p->state))
+      p->state = BCJ2_DEC_STATE_OK;
+    else
+    */
+    {
+      if (p->range < kTopValue)
+      {
+        if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC])
+        {
+          p->state = BCJ2_STREAM_RC;
+          p->temp = v;
+          return SZ_OK;
+        }
+        p->range <<= 8;
+        p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
+      }
+      {
+        const Byte *src = p->bufs[BCJ2_STREAM_MAIN];
+        const Byte *srcLim;
+        Byte *dest = p->dest;
+        {
+          const SizeT rem = (SizeT)(p->lims[BCJ2_STREAM_MAIN] - src);
+          SizeT num = (SizeT)(p->destLim - dest);
+          if (num >= rem)
+            num = rem;
+        #define NUM_ITERS 4
+        #if (NUM_ITERS & (NUM_ITERS - 1)) == 0
+          num &= ~((SizeT)NUM_ITERS - 1);   // if (NUM_ITERS == (1 << x))
+        #else
+          num -= num % NUM_ITERS; // if (NUM_ITERS != (1 << x))
+        #endif
+          srcLim = src + num;
+        }
+
+        #define NUM_SHIFT_BITS  24
+        #define ONE_ITER(indx) { \
+          const unsigned b = src[indx]; \
+          *dest++ = (Byte)b; \
+          v = (v << NUM_SHIFT_BITS) | b; \
+          if (((b + (0x100 - 0xe8)) & 0xfe) == 0) break; \
+          if (((v - (((UInt32)0x0f << (NUM_SHIFT_BITS)) + 0x80)) & \
+              ((((UInt32)1 << (4 + NUM_SHIFT_BITS)) - 0x1) << 4)) == 0) break; \
+            /* ++dest */; /* v = b; */ }
+          
+        if (src != srcLim)
+        for (;;)
+        {
+            /* The dependency chain of 2-cycle for (v) calculation is not big problem here.
+               But we can remove dependency chain with v = b in the end of loop. */
+          ONE_ITER(0)
+          #if (NUM_ITERS > 1)
+            ONE_ITER(1)
+          #if (NUM_ITERS > 2)
+            ONE_ITER(2)
+          #if (NUM_ITERS > 3)
+            ONE_ITER(3)
+          #if (NUM_ITERS > 4)
+            ONE_ITER(4)
+          #if (NUM_ITERS > 5)
+            ONE_ITER(5)
+          #if (NUM_ITERS > 6)
+            ONE_ITER(6)
+          #if (NUM_ITERS > 7)
+            ONE_ITER(7)
+          #endif
+          #endif
+          #endif
+          #endif
+          #endif
+          #endif
+          #endif
+          
+          src += NUM_ITERS;
+          if (src == srcLim)
+            break;
+        }
+
+        if (src == srcLim)
+      #if (NUM_ITERS > 1)
+        for (;;)
+      #endif
+        {
+        #if (NUM_ITERS > 1)
+          if (src == p->lims[BCJ2_STREAM_MAIN] || dest == p->destLim)
+        #endif
+          {
+            const SizeT num = (SizeT)(src - p->bufs[BCJ2_STREAM_MAIN]);
+            p->bufs[BCJ2_STREAM_MAIN] = src;
+            p->dest = dest;
+            p->ip += (UInt32)num;
+            /* state BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */
+            p->state =
+              src == p->lims[BCJ2_STREAM_MAIN] ?
+                (unsigned)BCJ2_STREAM_MAIN :
+                (unsigned)BCJ2_DEC_STATE_ORIG;
+            p->temp = v;
+            return SZ_OK;
+          }
+        #if (NUM_ITERS > 1)
+          ONE_ITER(0)
+          src++;
+        #endif
+        }
+
+        {
+          const SizeT num = (SizeT)(dest - p->dest);
+          p->dest = dest; // p->dest += num;
+          p->bufs[BCJ2_STREAM_MAIN] += num; // = src;
+          p->ip += (UInt32)num;
+        }
+        {
+          UInt32 bound, ttt;
+          CBcj2Prob *prob; // unsigned index;
+          /*
+          prob = p->probs + (unsigned)((Byte)v == 0xe8 ?
+              2 + (Byte)(v >> 8) :
+              ((v >> 5) & 1));  // ((Byte)v < 0xe8 ? 0 : 1));
+          */
+          {
+            const unsigned c = ((v + 0x17) >> 6) & 1;
+            prob = p->probs + (unsigned)
+                (((0 - c) & (Byte)(v >> NUM_SHIFT_BITS)) + c + ((v >> 5) & 1));
+                // (Byte)
+                // 8x->0     : e9->1     : xxe8->xx+2
+                // 8x->0x100 : e9->0x101 : xxe8->xx
+                // (((0x100 - (e & ~v)) & (0x100 | (v >> 8))) + (e & v));
+                // (((0x101 + (~e | v)) & (0x100 | (v >> 8))) + (e & v));
+          }
+          ttt = *prob;
+          bound = (p->range >> kNumBitModelTotalBits) * ttt;
+          if (p->code < bound)
+          {
+            // bcj2_stats[prob - p->probs][0]++;
+            p->range = bound;
+            *prob = (CBcj2Prob)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+            continue;
+          }
+          {
+            // bcj2_stats[prob - p->probs][1]++;
+            p->range -= bound;
+            p->code -= bound;
+            *prob = (CBcj2Prob)(ttt - (ttt >> kNumMoveBits));
+          }
+        }
+      }
+    }
+    {
+      /* (v == 0xe8 ? 0 : 1) uses setcc instruction with additional zero register usage in x64 MSVC. */
+      // const unsigned cj = ((Byte)v == 0xe8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP;
+      const unsigned cj = (((v + 0x57) >> 6) & 1) + BCJ2_STREAM_CALL;
+      const Byte *cur = p->bufs[cj];
+      Byte *dest;
+      SizeT rem;
+      if (cur == p->lims[cj])
+      {
+        p->state = cj;
+        break;
+      }
+      v = GetBe32a(cur);
+      p->bufs[cj] = cur + 4;
+      {
+        const UInt32 ip = p->ip + 4;
+        v -= ip;
+        p->ip = ip;
+      }
+      dest = p->dest;
+      rem = (SizeT)(p->destLim - dest);
+      if (rem < 4)
+      {
+        if ((unsigned)rem > 0) { dest[0] = (Byte)v;  v >>= 8;
+        if ((unsigned)rem > 1) { dest[1] = (Byte)v;  v >>= 8;
+        if ((unsigned)rem > 2) { dest[2] = (Byte)v;  v >>= 8; }}}
+        p->temp = v;
+        p->dest = dest + rem;
+        p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem;
+        break;
+      }
+      SetUi32(dest, v)
+      v >>= 24;
+      p->dest = dest + 4;
+    }
+  }
+
+  if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC])
+  {
+    p->range <<= 8;
+    p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
+  }
+  return SZ_OK;
+}
+
+#undef NUM_ITERS
+#undef ONE_ITER
+#undef NUM_SHIFT_BITS
+#undef kTopValue
+#undef kNumBitModelTotalBits
+#undef kBitModelTotal
+#undef kNumMoveBits

+ 332 - 0
Components/Lzma2/Bcj2.h

@@ -0,0 +1,332 @@
+/* Bcj2.h -- BCJ2 converter for x86 code (Branch CALL/JUMP variant2)
+2023-03-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_BCJ2_H
+#define ZIP7_INC_BCJ2_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define BCJ2_NUM_STREAMS 4
+
+enum
+{
+  BCJ2_STREAM_MAIN,
+  BCJ2_STREAM_CALL,
+  BCJ2_STREAM_JUMP,
+  BCJ2_STREAM_RC
+};
+
+enum
+{
+  BCJ2_DEC_STATE_ORIG_0 = BCJ2_NUM_STREAMS,
+  BCJ2_DEC_STATE_ORIG_1,
+  BCJ2_DEC_STATE_ORIG_2,
+  BCJ2_DEC_STATE_ORIG_3,
+  
+  BCJ2_DEC_STATE_ORIG,
+  BCJ2_DEC_STATE_ERROR     /* after detected data error */
+};
+
+enum
+{
+  BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS,
+  BCJ2_ENC_STATE_FINISHED  /* it's state after fully encoded stream */
+};
+
+
+/* #define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP) */
+#define BCJ2_IS_32BIT_STREAM(s) ((unsigned)((unsigned)(s) - (unsigned)BCJ2_STREAM_CALL) < 2)
+
+/*
+CBcj2Dec / CBcj2Enc
+bufs sizes:
+  BUF_SIZE(n) = lims[n] - bufs[n]
+bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be multiply of 4:
+    (BUF_SIZE(BCJ2_STREAM_CALL) & 3) == 0
+    (BUF_SIZE(BCJ2_STREAM_JUMP) & 3) == 0
+*/
+
+// typedef UInt32 CBcj2Prob;
+typedef UInt16 CBcj2Prob;
+
+/*
+BCJ2 encoder / decoder internal requirements:
+  - If last bytes of stream contain marker (e8/e8/0f8x), then
+    there is also encoded symbol (0 : no conversion) in RC stream.
+  - One case of overlapped instructions is supported,
+    if last byte of converted instruction is (0f) and next byte is (8x):
+      marker [xx xx xx 0f] 8x
+    then the pair (0f 8x) is treated as marker.
+*/
+
+/* ---------- BCJ2 Decoder ---------- */
+
+/*
+CBcj2Dec:
+(dest) is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following conditions:
+  bufs[BCJ2_STREAM_MAIN] >= dest &&
+  bufs[BCJ2_STREAM_MAIN] - dest >=
+        BUF_SIZE(BCJ2_STREAM_CALL) +
+        BUF_SIZE(BCJ2_STREAM_JUMP)
+  reserve = bufs[BCJ2_STREAM_MAIN] - dest -
+      ( BUF_SIZE(BCJ2_STREAM_CALL) +
+        BUF_SIZE(BCJ2_STREAM_JUMP) )
+  and additional conditions:
+  if (it's first call of Bcj2Dec_Decode() after Bcj2Dec_Init())
+  {
+    (reserve != 1) : if (ver <  v23.00)
+  }
+  else // if there are more than one calls of Bcj2Dec_Decode() after Bcj2Dec_Init())
+  {
+    (reserve >= 6) : if (ver <  v23.00)
+    (reserve >= 4) : if (ver >= v23.00)
+    We need that (reserve) because after first call of Bcj2Dec_Decode(),
+    CBcj2Dec::temp can contain up to 4 bytes for writing to (dest).
+  }
+  (reserve == 0) is allowed, if we decode full stream via single call of Bcj2Dec_Decode().
+  (reserve == 0) also is allowed in case of multi-call, if we use fixed buffers,
+     and (reserve) is calculated from full (final) sizes of all streams before first call.
+*/
+
+typedef struct
+{
+  const Byte *bufs[BCJ2_NUM_STREAMS];
+  const Byte *lims[BCJ2_NUM_STREAMS];
+  Byte *dest;
+  const Byte *destLim;
+
+  unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */
+
+  UInt32 ip;      /* property of starting base for decoding */
+  UInt32 temp;    /* Byte temp[4]; */
+  UInt32 range;
+  UInt32 code;
+  CBcj2Prob probs[2 + 256];
+} CBcj2Dec;
+
+
+/* Note:
+   Bcj2Dec_Init() sets (CBcj2Dec::ip = 0)
+   if (ip != 0) property is required, the caller must set CBcj2Dec::ip after Bcj2Dec_Init()
+*/
+void Bcj2Dec_Init(CBcj2Dec *p);
+
+
+/* Bcj2Dec_Decode():
+   returns:
+     SZ_OK
+     SZ_ERROR_DATA : if data in 5 starting bytes of BCJ2_STREAM_RC stream are not correct
+*/
+SRes Bcj2Dec_Decode(CBcj2Dec *p);
+
+/* To check that decoding was finished you can compare
+   sizes of processed streams with sizes known from another sources.
+   You must do at least one mandatory check from the two following options:
+      - the check for size of processed output (ORIG) stream.
+      - the check for size of processed input  (MAIN) stream.
+   additional optional checks:
+      - the checks for processed sizes of all input streams (MAIN, CALL, JUMP, RC)
+      - the checks Bcj2Dec_IsMaybeFinished*()
+   also before actual decoding you can check that the
+   following condition is met for stream sizes:
+     ( size(ORIG) == size(MAIN) + size(CALL) + size(JUMP) )
+*/
+
+/* (state == BCJ2_STREAM_MAIN) means that decoder is ready for
+      additional input data in BCJ2_STREAM_MAIN stream.
+   Note that (state == BCJ2_STREAM_MAIN) is allowed for non-finished decoding.
+*/
+#define Bcj2Dec_IsMaybeFinished_state_MAIN(_p_) ((_p_)->state == BCJ2_STREAM_MAIN)
+
+/* if the stream decoding was finished correctly, then range decoder
+   part of CBcj2Dec also was finished, and then (CBcj2Dec::code == 0).
+   Note that (CBcj2Dec::code == 0) is allowed for non-finished decoding.
+*/
+#define Bcj2Dec_IsMaybeFinished_code(_p_) ((_p_)->code == 0)
+
+/* use Bcj2Dec_IsMaybeFinished() only as additional check
+    after at least one mandatory check from the two following options:
+      - the check for size of processed output (ORIG) stream.
+      - the check for size of processed input  (MAIN) stream.
+*/
+#define Bcj2Dec_IsMaybeFinished(_p_) ( \
+        Bcj2Dec_IsMaybeFinished_state_MAIN(_p_) && \
+        Bcj2Dec_IsMaybeFinished_code(_p_))
+
+
+
+/* ---------- BCJ2 Encoder ---------- */
+
+typedef enum
+{
+  BCJ2_ENC_FINISH_MODE_CONTINUE,
+  BCJ2_ENC_FINISH_MODE_END_BLOCK,
+  BCJ2_ENC_FINISH_MODE_END_STREAM
+} EBcj2Enc_FinishMode;
+
+/*
+  BCJ2_ENC_FINISH_MODE_CONTINUE:
+     process non finished encoding.
+     It notifies the encoder that additional further calls
+     can provide more input data (src) than provided by current call.
+     In  that case the CBcj2Enc encoder still can move (src) pointer
+     up to (srcLim), but CBcj2Enc encoder can store some of the last
+     processed bytes (up to 4 bytes) from src to internal CBcj2Enc::temp[] buffer.
+   at return:
+       (CBcj2Enc::src will point to position that includes
+       processed data and data copied to (temp[]) buffer)
+       That data from (temp[]) buffer will be used in further calls.
+  
+  BCJ2_ENC_FINISH_MODE_END_BLOCK:
+     finish encoding of current block (ended at srcLim) without RC flushing.
+   at return: if (CBcj2Enc::state == BCJ2_ENC_STATE_ORIG) &&
+                  CBcj2Enc::src == CBcj2Enc::srcLim)
+        :  it shows that block encoding was finished. And the encoder is
+           ready for new (src) data or for stream finish operation.
+     finished block means
+     {
+       CBcj2Enc has completed block encoding up to (srcLim).
+       (1 + 4 bytes) or (2 + 4 bytes) CALL/JUMP cortages will
+       not cross block boundary at (srcLim).
+       temporary CBcj2Enc buffer for (ORIG) src data is empty.
+       3 output uncompressed streams (MAIN, CALL, JUMP) were flushed.
+       RC stream was not flushed. And RC stream will cross block boundary.
+     }
+     Note: some possible implementation of BCJ2 encoder could
+     write branch marker (e8/e8/0f8x) in one call of Bcj2Enc_Encode(),
+     and it could calculate symbol for RC in another call of Bcj2Enc_Encode().
+     BCJ2 encoder uses ip/fileIp/fileSize/relatLimit values to calculate RC symbol.
+     And these CBcj2Enc variables can have different values in different Bcj2Enc_Encode() calls.
+     So caller must finish each block with BCJ2_ENC_FINISH_MODE_END_BLOCK
+     to ensure that RC symbol is calculated and written in proper block.
+    
+  BCJ2_ENC_FINISH_MODE_END_STREAM
+     finish encoding of stream (ended at srcLim) fully including RC flushing.
+   at return: if (CBcj2Enc::state == BCJ2_ENC_STATE_FINISHED)
+        : it shows that stream encoding was finished fully,
+          and all output streams were flushed fully.
+     also Bcj2Enc_IsFinished() can be called.
+*/
+
+
+/*
+  32-bit relative offset in JUMP/CALL commands is
+    - (mod 4 GiB)  for 32-bit x86 code
+    - signed Int32 for 64-bit x86-64 code
+  BCJ2 encoder also does internal relative to absolute address conversions.
+  And there are 2 possible ways to do it:
+    before v23: we used 32-bit variables and (mod 4 GiB) conversion
+    since  v23: we use  64-bit variables and (signed Int32 offset) conversion.
+  The absolute address condition for conversion in v23:
+    ((UInt64)((Int64)ip64 - (Int64)fileIp64 + 5 + (Int32)offset) < (UInt64)fileSize64)
+  note that if (fileSize64 > 2 GiB). there is difference between
+  old (mod 4 GiB) way (v22) and new (signed Int32 offset) way (v23).
+  And new (v23) way is more suitable to encode 64-bit x86-64 code for (fileSize64 > 2 GiB) cases.
+*/
+
+/*
+// for old (v22) way for conversion:
+typedef UInt32 CBcj2Enc_ip_unsigned;
+typedef  Int32 CBcj2Enc_ip_signed;
+#define BCJ2_ENC_FileSize_MAX ((UInt32)1 << 31)
+*/
+typedef UInt64 CBcj2Enc_ip_unsigned;
+typedef  Int64 CBcj2Enc_ip_signed;
+
+/* maximum size of file that can be used for conversion condition */
+#define BCJ2_ENC_FileSize_MAX             ((CBcj2Enc_ip_unsigned)0 - 2)
+
+/* default value of fileSize64_minus1 variable that means
+   that absolute address limitation will not be used */
+#define BCJ2_ENC_FileSizeField_UNLIMITED  ((CBcj2Enc_ip_unsigned)0 - 1)
+
+/* calculate value that later can be set to CBcj2Enc::fileSize64_minus1 */
+#define BCJ2_ENC_GET_FileSizeField_VAL_FROM_FileSize(fileSize) \
+    ((CBcj2Enc_ip_unsigned)(fileSize) - 1)
+
+/* set CBcj2Enc::fileSize64_minus1 variable from size of file */
+#define Bcj2Enc_SET_FileSize(p, fileSize) \
+    (p)->fileSize64_minus1 = BCJ2_ENC_GET_FileSizeField_VAL_FROM_FileSize(fileSize);
+
+
+typedef struct
+{
+  Byte *bufs[BCJ2_NUM_STREAMS];
+  const Byte *lims[BCJ2_NUM_STREAMS];
+  const Byte *src;
+  const Byte *srcLim;
+
+  unsigned state;
+  EBcj2Enc_FinishMode finishMode;
+
+  Byte context;
+  Byte flushRem;
+  Byte isFlushState;
+
+  Byte cache;
+  UInt32 range;
+  UInt64 low;
+  UInt64 cacheSize;
+  
+  // UInt32 context;  // for marker version, it can include marker flag.
+
+  /* (ip64) and (fileIp64) correspond to virtual source stream position
+     that doesn't include data in temp[] */
+  CBcj2Enc_ip_unsigned ip64;         /* current (ip) position */
+  CBcj2Enc_ip_unsigned fileIp64;     /* start (ip) position of current file */
+  CBcj2Enc_ip_unsigned fileSize64_minus1;   /* size of current file (for conversion limitation) */
+  UInt32 relatLimit;  /* (relatLimit <= ((UInt32)1 << 31)) : 0 means disable_conversion */
+  // UInt32 relatExcludeBits;
+
+  UInt32 tempTarget;
+  unsigned tempPos; /* the number of bytes that were copied to temp[] buffer
+                       (tempPos <= 4) outside of Bcj2Enc_Encode() */
+  // Byte temp[4]; // for marker version
+  Byte temp[8];
+  CBcj2Prob probs[2 + 256];
+} CBcj2Enc;
+
+void Bcj2Enc_Init(CBcj2Enc *p);
+
+
+/*
+Bcj2Enc_Encode(): at exit:
+  p->State <  BCJ2_NUM_STREAMS    : we need more buffer space for output stream
+                                    (bufs[p->State] == lims[p->State])
+  p->State == BCJ2_ENC_STATE_ORIG : we need more data in input src stream
+                                    (src == srcLim)
+  p->State == BCJ2_ENC_STATE_FINISHED : after fully encoded stream
+*/
+void Bcj2Enc_Encode(CBcj2Enc *p);
+
+/* Bcj2Enc encoder can look ahead for up 4 bytes of source stream.
+   CBcj2Enc::tempPos : is the number of bytes that were copied from input stream to temp[] buffer.
+   (CBcj2Enc::src) after Bcj2Enc_Encode() is starting position after
+   fully processed data and after data copied to temp buffer.
+   So if the caller needs to get real number of fully processed input
+   bytes (without look ahead data in temp buffer),
+   the caller must subtruct (CBcj2Enc::tempPos) value from processed size
+   value that is calculated based on current (CBcj2Enc::src):
+     cur_processed_pos = Calc_Big_Processed_Pos(enc.src)) -
+        Bcj2Enc_Get_AvailInputSize_in_Temp(&enc);
+*/
+/* get the size of input data that was stored in temp[] buffer: */
+#define Bcj2Enc_Get_AvailInputSize_in_Temp(p) ((p)->tempPos)
+
+#define Bcj2Enc_IsFinished(p) ((p)->flushRem == 0)
+
+/* Note : the decoder supports overlapping of marker (0f 80).
+   But we can eliminate such overlapping cases by setting
+   the limit for relative offset conversion as
+     CBcj2Enc::relatLimit <= (0x0f << 24) == (240 MiB)
+*/
+/* default value for CBcj2Enc::relatLimit */
+#define BCJ2_ENC_RELAT_LIMIT_DEFAULT  ((UInt32)0x0f << 24)
+#define BCJ2_ENC_RELAT_LIMIT_MAX      ((UInt32)1 << 31)
+// #define BCJ2_RELAT_EXCLUDE_NUM_BITS 5
+
+EXTERN_C_END
+
+#endif

+ 709 - 0
Components/Lzma2/Bra.c

@@ -0,0 +1,709 @@
+/* Bra.c -- Branch converters for RISC code
+2024-01-20 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Bra.h"
+#include "RotateDefs.h"
+#include "CpuArch.h"
+
+#if defined(MY_CPU_SIZEOF_POINTER) \
+    && ( MY_CPU_SIZEOF_POINTER == 4 \
+      || MY_CPU_SIZEOF_POINTER == 8)
+  #define BR_CONV_USE_OPT_PC_PTR
+#endif
+
+#ifdef BR_CONV_USE_OPT_PC_PTR
+#define BR_PC_INIT  pc -= (UInt32)(SizeT)p;
+#define BR_PC_GET   (pc + (UInt32)(SizeT)p)
+#else
+#define BR_PC_INIT  pc += (UInt32)size;
+#define BR_PC_GET   (pc - (UInt32)(SizeT)(lim - p))
+// #define BR_PC_INIT
+// #define BR_PC_GET   (pc + (UInt32)(SizeT)(p - data))
+#endif
+
+#define BR_CONVERT_VAL(v, c) if (encoding) v += c; else v -= c;
+// #define BR_CONVERT_VAL(v, c) if (!encoding) c = (UInt32)0 - c; v += c;
+
+#define Z7_BRANCH_CONV(name) z7_ ## name
+
+#define Z7_BRANCH_FUNC_MAIN(name) \
+static \
+Z7_FORCE_INLINE \
+Z7_ATTRIB_NO_VECTOR \
+Byte *Z7_BRANCH_CONV(name)(Byte *p, SizeT size, UInt32 pc, int encoding)
+
+#define Z7_BRANCH_FUNC_IMP(name, m, encoding) \
+Z7_NO_INLINE \
+Z7_ATTRIB_NO_VECTOR \
+Byte *m(name)(Byte *data, SizeT size, UInt32 pc) \
+  { return Z7_BRANCH_CONV(name)(data, size, pc, encoding); } \
+
+#ifdef Z7_EXTRACT_ONLY
+#define Z7_BRANCH_FUNCS_IMP(name) \
+  Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_DEC_2, 0)
+#else
+#define Z7_BRANCH_FUNCS_IMP(name) \
+  Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_DEC_2, 0) \
+  Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_ENC_2, 1)
+#endif
+
+#if defined(__clang__)
+#define BR_EXTERNAL_FOR
+#define BR_NEXT_ITERATION  continue;
+#else
+#define BR_EXTERNAL_FOR    for (;;)
+#define BR_NEXT_ITERATION  break;
+#endif
+
+#if defined(__clang__) && (__clang_major__ >= 8) \
+  || defined(__GNUC__) && (__GNUC__ >= 1000) \
+  // GCC is not good for __builtin_expect() here
+  /* || defined(_MSC_VER) && (_MSC_VER >= 1920) */
+  // #define Z7_unlikely [[unlikely]]
+  // #define Z7_LIKELY(x)   (__builtin_expect((x), 1))
+  #define Z7_UNLIKELY(x) (__builtin_expect((x), 0))
+  // #define Z7_likely [[likely]]
+#else
+  // #define Z7_LIKELY(x)   (x)
+  #define Z7_UNLIKELY(x) (x)
+  // #define Z7_likely
+#endif
+
+
+Z7_BRANCH_FUNC_MAIN(BranchConv_ARM64)
+{
+  // Byte *p = data;
+  const Byte *lim;
+  const UInt32 flag = (UInt32)1 << (24 - 4);
+  const UInt32 mask = ((UInt32)1 << 24) - (flag << 1);
+  size &= ~(SizeT)3;
+  // if (size == 0) return p;
+  lim = p + size;
+  BR_PC_INIT
+  pc -= 4;  // because (p) will point to next instruction
+  
+  BR_EXTERNAL_FOR
+  {
+    // Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+    for (;;)
+    {
+      UInt32 v;
+      if Z7_UNLIKELY(p == lim)
+        return p;
+      v = GetUi32a(p);
+      p += 4;
+      if Z7_UNLIKELY(((v - 0x94000000) & 0xfc000000) == 0)
+      {
+        UInt32 c = BR_PC_GET >> 2;
+        BR_CONVERT_VAL(v, c)
+        v &= 0x03ffffff;
+        v |= 0x94000000;
+        SetUi32a(p - 4, v)
+        BR_NEXT_ITERATION
+      }
+      // v = rotlFixed(v, 8);  v += (flag << 8) - 0x90;  if Z7_UNLIKELY((v & ((mask << 8) + 0x9f)) == 0)
+      v -= 0x90000000;  if Z7_UNLIKELY((v & 0x9f000000) == 0)
+      {
+        UInt32 z, c;
+        // v = rotrFixed(v, 8);
+        v += flag; if Z7_UNLIKELY(v & mask) continue;
+        z = (v & 0xffffffe0) | (v >> 26);
+        c = (BR_PC_GET >> (12 - 3)) & ~(UInt32)7;
+        BR_CONVERT_VAL(z, c)
+        v &= 0x1f;
+        v |= 0x90000000;
+        v |= z << 26;
+        v |= 0x00ffffe0 & ((z & (((flag << 1) - 1))) - flag);
+        SetUi32a(p - 4, v)
+      }
+    }
+  }
+}
+Z7_BRANCH_FUNCS_IMP(BranchConv_ARM64)
+
+
+Z7_BRANCH_FUNC_MAIN(BranchConv_ARM)
+{
+  // Byte *p = data;
+  const Byte *lim;
+  size &= ~(SizeT)3;
+  lim = p + size;
+  BR_PC_INIT
+  /* in ARM: branch offset is relative to the +2 instructions from current instruction.
+     (p) will point to next instruction */
+  pc += 8 - 4;
+  
+  for (;;)
+  {
+    for (;;)
+    {
+      if Z7_UNLIKELY(p >= lim) { return p; }  p += 4;  if Z7_UNLIKELY(p[-1] == 0xeb) break;
+      if Z7_UNLIKELY(p >= lim) { return p; }  p += 4;  if Z7_UNLIKELY(p[-1] == 0xeb) break;
+    }
+    {
+      UInt32 v = GetUi32a(p - 4);
+      UInt32 c = BR_PC_GET >> 2;
+      BR_CONVERT_VAL(v, c)
+      v &= 0x00ffffff;
+      v |= 0xeb000000;
+      SetUi32a(p - 4, v)
+    }
+  }
+}
+Z7_BRANCH_FUNCS_IMP(BranchConv_ARM)
+
+
+Z7_BRANCH_FUNC_MAIN(BranchConv_PPC)
+{
+  // Byte *p = data;
+  const Byte *lim;
+  size &= ~(SizeT)3;
+  lim = p + size;
+  BR_PC_INIT
+  pc -= 4;  // because (p) will point to next instruction
+  
+  for (;;)
+  {
+    UInt32 v;
+    for (;;)
+    {
+      if Z7_UNLIKELY(p == lim)
+        return p;
+      // v = GetBe32a(p);
+      v = *(UInt32 *)(void *)p;
+      p += 4;
+      // if ((v & 0xfc000003) == 0x48000001) break;
+      // if ((p[-4] & 0xFC) == 0x48 && (p[-1] & 3) == 1) break;
+      if Z7_UNLIKELY(
+          ((v - Z7_CONV_BE_TO_NATIVE_CONST32(0x48000001))
+              & Z7_CONV_BE_TO_NATIVE_CONST32(0xfc000003)) == 0) break;
+    }
+    {
+      v = Z7_CONV_NATIVE_TO_BE_32(v);
+      {
+        UInt32 c = BR_PC_GET;
+        BR_CONVERT_VAL(v, c)
+      }
+      v &= 0x03ffffff;
+      v |= 0x48000000;
+      SetBe32a(p - 4, v)
+    }
+  }
+}
+Z7_BRANCH_FUNCS_IMP(BranchConv_PPC)
+
+
+#ifdef Z7_CPU_FAST_ROTATE_SUPPORTED
+#define BR_SPARC_USE_ROTATE
+#endif
+
+Z7_BRANCH_FUNC_MAIN(BranchConv_SPARC)
+{
+  // Byte *p = data;
+  const Byte *lim;
+  const UInt32 flag = (UInt32)1 << 22;
+  size &= ~(SizeT)3;
+  lim = p + size;
+  BR_PC_INIT
+  pc -= 4;  // because (p) will point to next instruction
+  for (;;)
+  {
+    UInt32 v;
+    for (;;)
+    {
+      if Z7_UNLIKELY(p == lim)
+        return p;
+      /* // the code without GetBe32a():
+      { const UInt32 v = GetUi16a(p) & 0xc0ff; p += 4; if (v == 0x40 || v == 0xc07f) break; }
+      */
+      v = GetBe32a(p);
+      p += 4;
+    #ifdef BR_SPARC_USE_ROTATE
+      v = rotlFixed(v, 2);
+      v += (flag << 2) - 1;
+      if Z7_UNLIKELY((v & (3 - (flag << 3))) == 0)
+    #else
+      v += (UInt32)5 << 29;
+      v ^= (UInt32)7 << 29;
+      v += flag;
+      if Z7_UNLIKELY((v & (0 - (flag << 1))) == 0)
+    #endif
+        break;
+    }
+    {
+      // UInt32 v = GetBe32a(p - 4);
+    #ifndef BR_SPARC_USE_ROTATE
+      v <<= 2;
+    #endif
+      {
+        UInt32 c = BR_PC_GET;
+        BR_CONVERT_VAL(v, c)
+      }
+      v &= (flag << 3) - 1;
+    #ifdef BR_SPARC_USE_ROTATE
+      v -= (flag << 2) - 1;
+      v = rotrFixed(v, 2);
+    #else
+      v -= (flag << 2);
+      v >>= 2;
+      v |= (UInt32)1 << 30;
+    #endif
+      SetBe32a(p - 4, v)
+    }
+  }
+}
+Z7_BRANCH_FUNCS_IMP(BranchConv_SPARC)
+
+
+Z7_BRANCH_FUNC_MAIN(BranchConv_ARMT)
+{
+  // Byte *p = data;
+  Byte *lim;
+  size &= ~(SizeT)1;
+  // if (size == 0) return p;
+  if (size <= 2) return p;
+  size -= 2;
+  lim = p + size;
+  BR_PC_INIT
+  /* in ARM: branch offset is relative to the +2 instructions from current instruction.
+     (p) will point to the +2 instructions from current instruction */
+  // pc += 4 - 4;
+  // if (encoding) pc -= 0xf800 << 1; else pc += 0xf800 << 1;
+  // #define ARMT_TAIL_PROC { goto armt_tail; }
+  #define ARMT_TAIL_PROC { return p; }
+  
+  do
+  {
+    /* in MSVC 32-bit x86 compilers:
+       UInt32 version : it loads value from memory with movzx
+       Byte   version : it loads value to 8-bit register (AL/CL)
+       movzx version is slightly faster in some cpus
+    */
+    unsigned b1;
+    // Byte / unsigned
+    b1 = p[1];
+    // optimized version to reduce one (p >= lim) check:
+    // unsigned a1 = p[1];  b1 = p[3];  p += 2;  if Z7_LIKELY((b1 & (a1 ^ 8)) < 0xf8)
+    for (;;)
+    {
+      unsigned b3; // Byte / UInt32
+      /* (Byte)(b3) normalization can use low byte computations in MSVC.
+         It gives smaller code, and no loss of speed in some compilers/cpus.
+         But new MSVC 32-bit x86 compilers use more slow load
+         from memory to low byte register in that case.
+         So we try to use full 32-bit computations for faster code.
+      */
+      // if (p >= lim) { ARMT_TAIL_PROC }  b3 = b1 + 8;  b1 = p[3];  p += 2;  if ((b3 & b1) >= 0xf8) break;
+      if Z7_UNLIKELY(p >= lim) { ARMT_TAIL_PROC }  b3 = p[3];  p += 2;  if Z7_UNLIKELY((b3 & (b1 ^ 8)) >= 0xf8) break;
+      if Z7_UNLIKELY(p >= lim) { ARMT_TAIL_PROC }  b1 = p[3];  p += 2;  if Z7_UNLIKELY((b1 & (b3 ^ 8)) >= 0xf8) break;
+    }
+    {
+      /* we can adjust pc for (0xf800) to rid of (& 0x7FF) operation.
+         But gcc/clang for arm64 can use bfi instruction for full code here */
+      UInt32 v =
+          ((UInt32)GetUi16a(p - 2) << 11) |
+          ((UInt32)GetUi16a(p) & 0x7FF);
+      /*
+      UInt32 v =
+            ((UInt32)p[1 - 2] << 19)
+          + (((UInt32)p[1] & 0x7) << 8)
+          + (((UInt32)p[-2] << 11))
+          + (p[0]);
+      */
+      p += 2;
+      {
+        UInt32 c = BR_PC_GET >> 1;
+        BR_CONVERT_VAL(v, c)
+      }
+      SetUi16a(p - 4, (UInt16)(((v >> 11) & 0x7ff) | 0xf000))
+      SetUi16a(p - 2, (UInt16)(v | 0xf800))
+      /*
+      p[-4] = (Byte)(v >> 11);
+      p[-3] = (Byte)(0xf0 | ((v >> 19) & 0x7));
+      p[-2] = (Byte)v;
+      p[-1] = (Byte)(0xf8 | (v >> 8));
+      */
+    }
+  }
+  while (p < lim);
+  return p;
+  // armt_tail:
+  // if ((Byte)((lim[1] & 0xf8)) != 0xf0) { lim += 2; }  return lim;
+  // return (Byte *)(lim + ((Byte)((lim[1] ^ 0xf0) & 0xf8) == 0 ? 0 : 2));
+  // return (Byte *)(lim + (((lim[1] ^ ~0xfu) & ~7u) == 0 ? 0 : 2));
+  // return (Byte *)(lim + 2 - (((((unsigned)lim[1] ^ 8) + 8) >> 7) & 2));
+}
+Z7_BRANCH_FUNCS_IMP(BranchConv_ARMT)
+
+
+// #define BR_IA64_NO_INLINE
+
+Z7_BRANCH_FUNC_MAIN(BranchConv_IA64)
+{
+  // Byte *p = data;
+  const Byte *lim;
+  size &= ~(SizeT)15;
+  lim = p + size;
+  pc -= 1 << 4;
+  pc >>= 4 - 1;
+  // pc -= 1 << 1;
+  
+  for (;;)
+  {
+    unsigned m;
+    for (;;)
+    {
+      if Z7_UNLIKELY(p == lim)
+        return p;
+      m = (unsigned)((UInt32)0x334b0000 >> (*p & 0x1e));
+      p += 16;
+      pc += 1 << 1;
+      if (m &= 3)
+        break;
+    }
+    {
+      p += (ptrdiff_t)m * 5 - 20; // negative value is expected here.
+      do
+      {
+        const UInt32 t =
+          #if defined(MY_CPU_X86_OR_AMD64)
+            // we use 32-bit load here to reduce code size on x86:
+            GetUi32(p);
+          #else
+            GetUi16(p);
+          #endif
+        UInt32 z = GetUi32(p + 1) >> m;
+        p += 5;
+        if (((t >> m) & (0x70 << 1)) == 0
+            && ((z - (0x5000000 << 1)) & (0xf000000 << 1)) == 0)
+        {
+          UInt32 v = (UInt32)((0x8fffff << 1) | 1) & z;
+          z ^= v;
+        #ifdef BR_IA64_NO_INLINE
+          v |= (v & ((UInt32)1 << (23 + 1))) >> 3;
+          {
+            UInt32 c = pc;
+            BR_CONVERT_VAL(v, c)
+          }
+          v &= (0x1fffff << 1) | 1;
+        #else
+          {
+            if (encoding)
+            {
+              // pc &= ~(0xc00000 << 1); // we just need to clear at least 2 bits
+              pc &= (0x1fffff << 1) | 1;
+              v += pc;
+            }
+            else
+            {
+              // pc |= 0xc00000 << 1; // we need to set at least 2 bits
+              pc |= ~(UInt32)((0x1fffff << 1) | 1);
+              v -= pc;
+            }
+          }
+          v &= ~(UInt32)(0x600000 << 1);
+        #endif
+          v += (0x700000 << 1);
+          v &= (0x8fffff << 1) | 1;
+          z |= v;
+          z <<= m;
+          SetUi32(p + 1 - 5, z)
+        }
+        m++;
+      }
+      while (m &= 3); // while (m < 4);
+    }
+  }
+}
+Z7_BRANCH_FUNCS_IMP(BranchConv_IA64)
+
+
+#define BR_CONVERT_VAL_ENC(v)  v += BR_PC_GET;
+#define BR_CONVERT_VAL_DEC(v)  v -= BR_PC_GET;
+
+#if 1 && defined(MY_CPU_LE_UNALIGN)
+  #define RISCV_USE_UNALIGNED_LOAD
+#endif
+
+#ifdef RISCV_USE_UNALIGNED_LOAD
+  #define RISCV_GET_UI32(p)      GetUi32(p)
+  #define RISCV_SET_UI32(p, v)   { SetUi32(p, v) }
+#else
+  #define RISCV_GET_UI32(p) \
+    ((UInt32)GetUi16a(p) + \
+    ((UInt32)GetUi16a((p) + 2) << 16))
+  #define RISCV_SET_UI32(p, v) { \
+    SetUi16a(p, (UInt16)(v)) \
+    SetUi16a((p) + 2, (UInt16)(v >> 16)) }
+#endif
+
+#if 1 && defined(MY_CPU_LE)
+  #define RISCV_USE_16BIT_LOAD
+#endif
+
+#ifdef RISCV_USE_16BIT_LOAD
+  #define RISCV_LOAD_VAL(p)  GetUi16a(p)
+#else
+  #define RISCV_LOAD_VAL(p)  (*(p))
+#endif
+
+#define RISCV_INSTR_SIZE  2
+#define RISCV_STEP_1      (4 + RISCV_INSTR_SIZE)
+#define RISCV_STEP_2      4
+#define RISCV_REG_VAL     (2 << 7)
+#define RISCV_CMD_VAL     3
+#if 1
+  // for code size optimization:
+  #define RISCV_DELTA_7F  0x7f
+#else
+  #define RISCV_DELTA_7F  0
+#endif
+
+#define RISCV_CHECK_1(v, b) \
+    (((((b) - RISCV_CMD_VAL) ^ ((v) << 8)) & (0xf8000 + RISCV_CMD_VAL)) == 0)
+
+#if 1
+  #define RISCV_CHECK_2(v, r) \
+    ((((v) - ((RISCV_CMD_VAL << 12) | RISCV_REG_VAL | 8)) \
+           << 18) \
+     < ((r) & 0x1d))
+#else
+  // this branch gives larger code, because
+  // compilers generate larger code for big constants.
+  #define RISCV_CHECK_2(v, r) \
+    ((((v) - ((RISCV_CMD_VAL << 12) | RISCV_REG_VAL)) \
+           & ((RISCV_CMD_VAL << 12) | RISCV_REG_VAL)) \
+     < ((r) & 0x1d))
+#endif
+
+
+#define RISCV_SCAN_LOOP \
+  Byte *lim; \
+  size &= ~(SizeT)(RISCV_INSTR_SIZE - 1); \
+  if (size <= 6) return p; \
+  size -= 6; \
+  lim = p + size; \
+  BR_PC_INIT \
+  for (;;) \
+  { \
+    UInt32 a, v; \
+    /* Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE */ \
+    for (;;) \
+    { \
+      if Z7_UNLIKELY(p >= lim) { return p; } \
+      a = (RISCV_LOAD_VAL(p) ^ 0x10u) + 1; \
+      if ((a & 0x77) == 0) break; \
+      a = (RISCV_LOAD_VAL(p + RISCV_INSTR_SIZE) ^ 0x10u) + 1; \
+      p += RISCV_INSTR_SIZE * 2; \
+      if ((a & 0x77) == 0) \
+      { \
+        p -= RISCV_INSTR_SIZE; \
+        if Z7_UNLIKELY(p >= lim) { return p; } \
+        break; \
+      } \
+    }
+// (xx6f ^ 10) + 1 = xx7f + 1 = xx80       : JAL
+// (xxef ^ 10) + 1 = xxff + 1 = xx00 + 100 : JAL
+// (xx17 ^ 10) + 1 = xx07 + 1 = xx08       : AUIPC
+// (xx97 ^ 10) + 1 = xx87 + 1 = xx88       : AUIPC
+
+Byte * Z7_BRANCH_CONV_ENC(RISCV)(Byte *p, SizeT size, UInt32 pc)
+{
+  RISCV_SCAN_LOOP
+    v = a;
+    a = RISCV_GET_UI32(p);
+#ifndef RISCV_USE_16BIT_LOAD
+    v += (UInt32)p[1] << 8;
+#endif
+
+    if ((v & 8) == 0) // JAL
+    {
+      if ((v - (0x100 /* - RISCV_DELTA_7F */)) & 0xd80)
+      {
+        p += RISCV_INSTR_SIZE;
+        continue;
+      }
+      {
+        v = ((a &    1u << 31) >> 11)
+          | ((a & 0x3ff << 21) >> 20)
+          | ((a &     1 << 20) >> 9)
+          |  (a &  0xff << 12);
+        BR_CONVERT_VAL_ENC(v)
+        // ((v & 1) == 0)
+        // v: bits [1 : 20] contain offset bits
+#if 0 && defined(RISCV_USE_UNALIGNED_LOAD)
+        a &= 0xfff;
+        a |= ((UInt32)(v << 23))
+          |  ((UInt32)(v <<  7) & ((UInt32)0xff << 16))
+          |  ((UInt32)(v >>  5) & ((UInt32)0xf0 << 8));
+        RISCV_SET_UI32(p, a)
+#else // aligned
+#if 0
+        SetUi16a(p, (UInt16)(((v >> 5) & 0xf000) | (a & 0xfff)))
+#else
+        p[1] = (Byte)(((v >> 13) & 0xf0) | ((a >> 8) & 0xf));
+#endif
+
+#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE)
+        v <<= 15;
+        v = Z7_BSWAP32(v);
+        SetUi16a(p + 2, (UInt16)v)
+#else
+        p[2] = (Byte)(v >> 9);
+        p[3] = (Byte)(v >> 1);
+#endif
+#endif // aligned
+      }
+      p += 4;
+      continue;
+    } // JAL
+
+    {
+      // AUIPC
+      if (v & 0xe80)  // (not x0) and (not x2)
+      {
+        const UInt32 b = RISCV_GET_UI32(p + 4);
+        if (RISCV_CHECK_1(v, b))
+        {
+          {
+            const UInt32 temp = (b << 12) | (0x17 + RISCV_REG_VAL);
+            RISCV_SET_UI32(p, temp)
+          }
+          a &= 0xfffff000;
+          {
+#if 1
+          const int t = -1 >> 1;
+          if (t != -1)
+            a += (b >> 20) - ((b >> 19) & 0x1000); // arithmetic right shift emulation
+          else
+#endif
+            a += (UInt32)((Int32)b >> 20); // arithmetic right shift (sign-extension).
+          }
+          BR_CONVERT_VAL_ENC(a)
+#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE)
+          a = Z7_BSWAP32(a);
+          RISCV_SET_UI32(p + 4, a)
+#else
+          SetBe32(p + 4, a)
+#endif
+          p += 8;
+        }
+        else
+          p += RISCV_STEP_1;
+      }
+      else
+      {
+        UInt32 r = a >> 27;
+        if (RISCV_CHECK_2(v, r))
+        {
+          v = RISCV_GET_UI32(p + 4);
+          r = (r << 7) + 0x17 + (v & 0xfffff000);
+          a = (a >> 12) | (v << 20);
+          RISCV_SET_UI32(p, r)
+          RISCV_SET_UI32(p + 4, a)
+          p += 8;
+        }
+        else
+          p += RISCV_STEP_2;
+      }
+    }
+  } // for
+}
+
+
+Byte * Z7_BRANCH_CONV_DEC(RISCV)(Byte *p, SizeT size, UInt32 pc)
+{
+  RISCV_SCAN_LOOP
+#ifdef RISCV_USE_16BIT_LOAD
+    if ((a & 8) == 0)
+    {
+#else
+    v = a;
+    a += (UInt32)p[1] << 8;
+    if ((v & 8) == 0)
+    {
+#endif
+      // JAL
+      a -= 0x100 - RISCV_DELTA_7F;
+      if (a & 0xd80)
+      {
+        p += RISCV_INSTR_SIZE;
+        continue;
+      }
+      {
+        const UInt32 a_old = (a + (0xef - RISCV_DELTA_7F)) & 0xfff;
+#if 0 // unaligned
+        a = GetUi32(p);
+        v = (UInt32)(a >> 23) & ((UInt32)0xff << 1)
+          | (UInt32)(a >>  7) & ((UInt32)0xff << 9)
+#elif 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE)
+        v = GetUi16a(p + 2);
+        v = Z7_BSWAP32(v) >> 15
+#else
+        v = (UInt32)p[3] << 1
+          | (UInt32)p[2] << 9
+#endif
+          | (UInt32)((a & 0xf000) << 5);
+        BR_CONVERT_VAL_DEC(v)
+        a = a_old
+          | (v << 11 &    1u << 31)
+          | (v << 20 & 0x3ff << 21)
+          | (v <<  9 &     1 << 20)
+          | (v       &  0xff << 12);
+        RISCV_SET_UI32(p, a)
+      }
+      p += 4;
+      continue;
+    } // JAL
+
+    {
+      // AUIPC
+      v = a;
+#if 1 && defined(RISCV_USE_UNALIGNED_LOAD)
+      a = GetUi32(p);
+#else
+      a |= (UInt32)GetUi16a(p + 2) << 16;
+#endif
+      if ((v & 0xe80) == 0)  // x0/x2
+      {
+        const UInt32 r = a >> 27;
+        if (RISCV_CHECK_2(v, r))
+        {
+          UInt32 b;
+#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE)
+          b = RISCV_GET_UI32(p + 4);
+          b = Z7_BSWAP32(b);
+#else
+          b = GetBe32(p + 4);
+#endif
+          v = a >> 12;
+          BR_CONVERT_VAL_DEC(b)
+          a = (r << 7) + 0x17;
+          a += (b + 0x800) & 0xfffff000;
+          v |= b << 20;
+          RISCV_SET_UI32(p, a)
+          RISCV_SET_UI32(p + 4, v)
+          p += 8;
+        }
+        else
+          p += RISCV_STEP_2;
+      }
+      else
+      {
+        const UInt32 b = RISCV_GET_UI32(p + 4);
+        if (!RISCV_CHECK_1(v, b))
+          p += RISCV_STEP_1;
+        else
+        {
+          v = (a & 0xfffff000) | (b >> 20);
+          a = (b << 12) | (0x17 + RISCV_REG_VAL);
+          RISCV_SET_UI32(p, a)
+          RISCV_SET_UI32(p + 4, v)
+          p += 8;
+        }
+      }
+    }
+  } // for
+}

+ 105 - 0
Components/Lzma2/Bra.h

@@ -0,0 +1,105 @@
+/* Bra.h -- Branch converters for executables
+2024-01-20 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_BRA_H
+#define ZIP7_INC_BRA_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/* #define PPC BAD_PPC_11 // for debug */
+
+#define Z7_BRANCH_CONV_DEC_2(name)  z7_ ## name ## _Dec
+#define Z7_BRANCH_CONV_ENC_2(name)  z7_ ## name ## _Enc
+#define Z7_BRANCH_CONV_DEC(name)    Z7_BRANCH_CONV_DEC_2(BranchConv_ ## name)
+#define Z7_BRANCH_CONV_ENC(name)    Z7_BRANCH_CONV_ENC_2(BranchConv_ ## name)
+#define Z7_BRANCH_CONV_ST_DEC(name) z7_BranchConvSt_ ## name ## _Dec
+#define Z7_BRANCH_CONV_ST_ENC(name) z7_BranchConvSt_ ## name ## _Enc
+
+#define Z7_BRANCH_CONV_DECL(name)    Byte * name(Byte *data, SizeT size, UInt32 pc)
+#define Z7_BRANCH_CONV_ST_DECL(name) Byte * name(Byte *data, SizeT size, UInt32 pc, UInt32 *state)
+
+typedef Z7_BRANCH_CONV_DECL(   (*z7_Func_BranchConv));
+typedef Z7_BRANCH_CONV_ST_DECL((*z7_Func_BranchConvSt));
+
+#define Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL 0
+Z7_BRANCH_CONV_ST_DECL (Z7_BRANCH_CONV_ST_DEC(X86));
+Z7_BRANCH_CONV_ST_DECL (Z7_BRANCH_CONV_ST_ENC(X86));
+
+#define Z7_BRANCH_FUNCS_DECL(name) \
+Z7_BRANCH_CONV_DECL (Z7_BRANCH_CONV_DEC_2(name)); \
+Z7_BRANCH_CONV_DECL (Z7_BRANCH_CONV_ENC_2(name));
+
+Z7_BRANCH_FUNCS_DECL (BranchConv_ARM64)
+Z7_BRANCH_FUNCS_DECL (BranchConv_ARM)
+Z7_BRANCH_FUNCS_DECL (BranchConv_ARMT)
+Z7_BRANCH_FUNCS_DECL (BranchConv_PPC)
+Z7_BRANCH_FUNCS_DECL (BranchConv_SPARC)
+Z7_BRANCH_FUNCS_DECL (BranchConv_IA64)
+Z7_BRANCH_FUNCS_DECL (BranchConv_RISCV)
+
+/*
+These functions convert data that contain CPU instructions.
+Each such function converts relative addresses to absolute addresses in some
+branch instructions: CALL (in all converters) and JUMP (X86 converter only).
+Such conversion allows to increase compression ratio, if we compress that data.
+
+There are 2 types of converters:
+  Byte * Conv_RISC (Byte *data, SizeT size, UInt32 pc);
+  Byte * ConvSt_X86(Byte *data, SizeT size, UInt32 pc, UInt32 *state);
+Each Converter supports 2 versions: one for encoding
+and one for decoding (_Enc/_Dec postfixes in function name).
+
+In params:
+  data  : data buffer
+  size  : size of data
+  pc    : current virtual Program Counter (Instruction Pointer) value
+In/Out param:
+  state : pointer to state variable (for X86 converter only)
+
+Return:
+  The pointer to position in (data) buffer after last byte that was processed.
+  If the caller calls converter again, it must call it starting with that position.
+  But the caller is allowed to move data in buffer. So pointer to
+  current processed position also will be changed for next call.
+  Also the caller must increase internal (pc) value for next call.
+  
+Each converter has some characteristics: Endian, Alignment, LookAhead.
+  Type   Endian  Alignment  LookAhead
+  
+  X86    little      1          4
+  ARMT   little      2          2
+  RISCV  little      2          6
+  ARM    little      4          0
+  ARM64  little      4          0
+  PPC     big        4          0
+  SPARC   big        4          0
+  IA64   little     16          0
+
+  (data) must be aligned for (Alignment).
+  processed size can be calculated as:
+    SizeT processed = Conv(data, size, pc) - data;
+  if (processed == 0)
+    it means that converter needs more data for processing.
+  If (size < Alignment + LookAhead)
+    then (processed == 0) is allowed.
+
+Example code for conversion in loop:
+  UInt32 pc = 0;
+  size = 0;
+  for (;;)
+  {
+    size += Load_more_input_data(data + size);
+    SizeT processed = Conv(data, size, pc) - data;
+    if (processed == 0 && no_more_input_data_after_size)
+      break; // we stop convert loop
+    data += processed;
+    size -= processed;
+    pc += processed;
+  }
+*/
+
+EXTERN_C_END
+
+#endif

+ 187 - 0
Components/Lzma2/Bra86.c

@@ -0,0 +1,187 @@
+/* Bra86.c -- Branch converter for X86 code (BCJ)
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Bra.h"
+#include "CpuArch.h"
+
+
+#if defined(MY_CPU_SIZEOF_POINTER) \
+    && ( MY_CPU_SIZEOF_POINTER == 4 \
+      || MY_CPU_SIZEOF_POINTER == 8)
+  #define BR_CONV_USE_OPT_PC_PTR
+#endif
+
+#ifdef BR_CONV_USE_OPT_PC_PTR
+#define BR_PC_INIT  pc -= (UInt32)(SizeT)p; // (MY_uintptr_t)
+#define BR_PC_GET   (pc + (UInt32)(SizeT)p)
+#else
+#define BR_PC_INIT  pc += (UInt32)size;
+#define BR_PC_GET   (pc - (UInt32)(SizeT)(lim - p))
+// #define BR_PC_INIT
+// #define BR_PC_GET   (pc + (UInt32)(SizeT)(p - data))
+#endif
+
+#define BR_CONVERT_VAL(v, c) if (encoding) v += c; else v -= c;
+// #define BR_CONVERT_VAL(v, c) if (!encoding) c = (UInt32)0 - c; v += c;
+
+#define Z7_BRANCH_CONV_ST(name) z7_BranchConvSt_ ## name
+
+#define BR86_NEED_CONV_FOR_MS_BYTE(b) ((((b) + 1) & 0xfe) == 0)
+
+#ifdef MY_CPU_LE_UNALIGN
+  #define BR86_PREPARE_BCJ_SCAN  const UInt32 v = GetUi32(p) ^ 0xe8e8e8e8;
+  #define BR86_IS_BCJ_BYTE(n)    ((v & ((UInt32)0xfe << (n) * 8)) == 0)
+#else
+  #define BR86_PREPARE_BCJ_SCAN
+  // bad for MSVC X86 (partial write to byte reg):
+  #define BR86_IS_BCJ_BYTE(n)    ((p[n - 4] & 0xfe) == 0xe8)
+  // bad for old MSVC (partial write to byte reg):
+  // #define BR86_IS_BCJ_BYTE(n)    (((*p ^ 0xe8) & 0xfe) == 0)
+#endif
+ 
+static
+Z7_FORCE_INLINE
+Z7_ATTRIB_NO_VECTOR
+Byte *Z7_BRANCH_CONV_ST(X86)(Byte *p, SizeT size, UInt32 pc, UInt32 *state, int encoding)
+{
+  if (size < 5)
+    return p;
+ {
+  // Byte *p = data;
+  const Byte *lim = p + size - 4;
+  unsigned mask = (unsigned)*state;  // & 7;
+#ifdef BR_CONV_USE_OPT_PC_PTR
+  /* if BR_CONV_USE_OPT_PC_PTR is defined: we need to adjust (pc) for (+4),
+        because call/jump offset is relative to the next instruction.
+     if BR_CONV_USE_OPT_PC_PTR is not defined : we don't need to adjust (pc) for (+4),
+         because  BR_PC_GET uses (pc - (lim - p)), and lim was adjusted for (-4) before.
+  */
+  pc += 4;
+#endif
+  BR_PC_INIT
+  goto start;
+
+  for (;; mask |= 4)
+  {
+    // cont: mask |= 4;
+  start:
+    if (p >= lim)
+      goto fin;
+    {
+      BR86_PREPARE_BCJ_SCAN
+      p += 4;
+      if (BR86_IS_BCJ_BYTE(0))  { goto m0; }  mask >>= 1;
+      if (BR86_IS_BCJ_BYTE(1))  { goto m1; }  mask >>= 1;
+      if (BR86_IS_BCJ_BYTE(2))  { goto m2; }  mask = 0;
+      if (BR86_IS_BCJ_BYTE(3))  { goto a3; }
+    }
+    goto main_loop;
+
+  m0: p--;
+  m1: p--;
+  m2: p--;
+    if (mask == 0)
+      goto a3;
+    if (p > lim)
+      goto fin_p;
+   
+    // if (((0x17u >> mask) & 1) == 0)
+    if (mask > 4 || mask == 3)
+    {
+      mask >>= 1;
+      continue; // goto cont;
+    }
+    mask >>= 1;
+    if (BR86_NEED_CONV_FOR_MS_BYTE(p[mask]))
+      continue; // goto cont;
+    // if (!BR86_NEED_CONV_FOR_MS_BYTE(p[3])) continue; // goto cont;
+    {
+      UInt32 v = GetUi32(p);
+      UInt32 c;
+      v += (1 << 24);  if (v & 0xfe000000) continue; // goto cont;
+      c = BR_PC_GET;
+      BR_CONVERT_VAL(v, c)
+      {
+        mask <<= 3;
+        if (BR86_NEED_CONV_FOR_MS_BYTE(v >> mask))
+        {
+          v ^= (((UInt32)0x100 << mask) - 1);
+          #ifdef MY_CPU_X86
+          // for X86 : we can recalculate (c) to reduce register pressure
+            c = BR_PC_GET;
+          #endif
+          BR_CONVERT_VAL(v, c)
+        }
+        mask = 0;
+      }
+      // v = (v & ((1 << 24) - 1)) - (v & (1 << 24));
+      v &= (1 << 25) - 1;  v -= (1 << 24);
+      SetUi32(p, v)
+      p += 4;
+      goto main_loop;
+    }
+
+  main_loop:
+    if (p >= lim)
+      goto fin;
+    for (;;)
+    {
+      BR86_PREPARE_BCJ_SCAN
+      p += 4;
+      if (BR86_IS_BCJ_BYTE(0))  { goto a0; }
+      if (BR86_IS_BCJ_BYTE(1))  { goto a1; }
+      if (BR86_IS_BCJ_BYTE(2))  { goto a2; }
+      if (BR86_IS_BCJ_BYTE(3))  { goto a3; }
+      if (p >= lim)
+        goto fin;
+    }
+  
+  a0: p--;
+  a1: p--;
+  a2: p--;
+  a3:
+    if (p > lim)
+      goto fin_p;
+    // if (!BR86_NEED_CONV_FOR_MS_BYTE(p[3])) continue; // goto cont;
+    {
+      UInt32 v = GetUi32(p);
+      UInt32 c;
+      v += (1 << 24);  if (v & 0xfe000000) continue; // goto cont;
+      c = BR_PC_GET;
+      BR_CONVERT_VAL(v, c)
+      // v = (v & ((1 << 24) - 1)) - (v & (1 << 24));
+      v &= (1 << 25) - 1;  v -= (1 << 24);
+      SetUi32(p, v)
+      p += 4;
+      goto main_loop;
+    }
+  }
+
+fin_p:
+  p--;
+fin:
+  // the following processing for tail is optional and can be commented
+  /*
+  lim += 4;
+  for (; p < lim; p++, mask >>= 1)
+    if ((*p & 0xfe) == 0xe8)
+      break;
+  */
+  *state = (UInt32)mask;
+  return p;
+ }
+}
+
+
+#define Z7_BRANCH_CONV_ST_FUNC_IMP(name, m, encoding) \
+Z7_NO_INLINE \
+Z7_ATTRIB_NO_VECTOR \
+Byte *m(name)(Byte *data, SizeT size, UInt32 pc, UInt32 *state) \
+  { return Z7_BRANCH_CONV_ST(name)(data, size, pc, state, encoding); }
+
+Z7_BRANCH_CONV_ST_FUNC_IMP(X86, Z7_BRANCH_CONV_ST_DEC, 0)
+#ifndef Z7_EXTRACT_ONLY
+Z7_BRANCH_CONV_ST_FUNC_IMP(X86, Z7_BRANCH_CONV_ST_ENC, 1)
+#endif

+ 169 - 0
Components/Lzma2/Delta.c

@@ -0,0 +1,169 @@
+/* Delta.c -- Delta converter
+2021-02-09 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Delta.h"
+
+void Delta_Init(Byte *state)
+{
+  unsigned i;
+  for (i = 0; i < DELTA_STATE_SIZE; i++)
+    state[i] = 0;
+}
+
+
+void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size)
+{
+  Byte temp[DELTA_STATE_SIZE];
+
+  if (size == 0)
+    return;
+
+  {
+    unsigned i = 0;
+    do
+      temp[i] = state[i];
+    while (++i != delta);
+  }
+
+  if (size <= delta)
+  {
+    unsigned i = 0, k;
+    do
+    {
+      Byte b = *data;
+      *data++ = (Byte)(b - temp[i]);
+      temp[i] = b;
+    }
+    while (++i != size);
+    
+    k = 0;
+    
+    do
+    {
+      if (i == delta)
+        i = 0;
+      state[k] = temp[i++];
+    }
+    while (++k != delta);
+    
+    return;
+  }
+    
+  {
+    Byte *p = data + size - delta;
+    {
+      unsigned i = 0;
+      do
+        state[i] = *p++;
+      while (++i != delta);
+    }
+    {
+      const Byte *lim = data + delta;
+      ptrdiff_t dif = -(ptrdiff_t)delta;
+      
+      if (((ptrdiff_t)size + dif) & 1)
+      {
+        --p;  *p = (Byte)(*p - p[dif]);
+      }
+
+      while (p != lim)
+      {
+        --p;  *p = (Byte)(*p - p[dif]);
+        --p;  *p = (Byte)(*p - p[dif]);
+      }
+      
+      dif = -dif;
+      
+      do
+      {
+        --p;  *p = (Byte)(*p - temp[--dif]);
+      }
+      while (dif != 0);
+    }
+  }
+}
+
+
+void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size)
+{
+  unsigned i;
+  const Byte *lim;
+
+  if (size == 0)
+    return;
+  
+  i = 0;
+  lim = data + size;
+  
+  if (size <= delta)
+  {
+    do
+      *data = (Byte)(*data + state[i++]);
+    while (++data != lim);
+
+    for (; delta != i; state++, delta--)
+      *state = state[i];
+    data -= i;
+  }
+  else
+  {
+    /*
+    #define B(n) b ## n
+    #define I(n) Byte B(n) = state[n];
+    #define U(n) { B(n) = (Byte)((B(n)) + *data++); data[-1] = (B(n)); }
+    #define F(n) if (data != lim) { U(n) }
+
+    if (delta == 1)
+    {
+      I(0)
+      if ((lim - data) & 1) { U(0) }
+      while (data != lim) { U(0) U(0) }
+      data -= 1;
+    }
+    else if (delta == 2)
+    {
+      I(0) I(1)
+      lim -= 1; while (data < lim) { U(0) U(1) }
+      lim += 1; F(0)
+      data -= 2;
+    }
+    else if (delta == 3)
+    {
+      I(0) I(1) I(2)
+      lim -= 2; while (data < lim) { U(0) U(1) U(2) }
+      lim += 2; F(0) F(1)
+      data -= 3;
+    }
+    else if (delta == 4)
+    {
+      I(0) I(1) I(2) I(3)
+      lim -= 3; while (data < lim) { U(0) U(1) U(2) U(3) }
+      lim += 3; F(0) F(1) F(2)
+      data -= 4;
+    }
+    else
+    */
+    {
+      do
+      {
+        *data = (Byte)(*data + state[i++]);
+        data++;
+      }
+      while (i != delta);
+  
+      {
+        ptrdiff_t dif = -(ptrdiff_t)delta;
+        do
+          *data = (Byte)(*data + data[dif]);
+        while (++data != lim);
+        data += dif;
+      }
+    }
+  }
+
+  do
+    *state++ = *data;
+  while (++data != lim);
+}

+ 19 - 0
Components/Lzma2/Delta.h

@@ -0,0 +1,19 @@
+/* Delta.h -- Delta converter
+2023-03-03 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_DELTA_H
+#define ZIP7_INC_DELTA_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define DELTA_STATE_SIZE 256
+
+void Delta_Init(Byte *state);
+void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size);
+void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size);
+
+EXTERN_C_END
+
+#endif

+ 50 - 0
Components/Lzma2/RotateDefs.h

@@ -0,0 +1,50 @@
+/* RotateDefs.h -- Rotate functions
+2023-06-18 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_ROTATE_DEFS_H
+#define ZIP7_INC_ROTATE_DEFS_H
+
+#ifdef _MSC_VER
+
+#include <stdlib.h>
+
+/* don't use _rotl with old MINGW. It can insert slow call to function. */
+ 
+/* #if (_MSC_VER >= 1200) */
+#pragma intrinsic(_rotl)
+#pragma intrinsic(_rotr)
+/* #endif */
+
+#define rotlFixed(x, n) _rotl((x), (n))
+#define rotrFixed(x, n) _rotr((x), (n))
+
+#if (_MSC_VER >= 1300)
+#define Z7_ROTL64(x, n) _rotl64((x), (n))
+#define Z7_ROTR64(x, n) _rotr64((x), (n))
+#else
+#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n))))
+#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (64 - (n))))
+#endif
+
+#else
+
+/* new compilers can translate these macros to fast commands. */
+
+#if defined(__clang__) && (__clang_major__ >= 4) \
+  || defined(__GNUC__) && (__GNUC__ >= 5)
+/* GCC 4.9.0 and clang 3.5 can recognize more correct version: */
+#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (-(n) & 31)))
+#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (-(n) & 31)))
+#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (-(n) & 63)))
+#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (-(n) & 63)))
+#else
+/* for old GCC / clang: */
+#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
+#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n))))
+#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (64 - (n))))
+#endif
+
+#endif
+
+#endif

+ 889 - 0
Components/Lzma2/Util/7z/7zMain.c

@@ -0,0 +1,889 @@
+/* 7zMain.c - Test application for 7z Decoder
+2024-02-28 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#ifndef USE_WINDOWS_FILE
+/* for mkdir */
+#ifdef _WIN32
+#include <direct.h>
+#else
+#include <stdlib.h>
+#include <time.h>
+#ifdef __GNUC__
+#include <sys/time.h>
+#endif
+#include <fcntl.h>
+// #include <utime.h>
+#include <sys/stat.h>
+#include <errno.h>
+#endif
+#endif
+
+#include "../../7zFile.h"
+#include "../../7z.h"
+#include "../../7zAlloc.h"
+#include "../../7zBuf.h"
+#include "../../7zCrc.h"
+#include "../../7zVersion.h"
+
+#include "../../CpuArch.h"
+
+#define kInputBufSize ((size_t)1 << 18)
+
+static const ISzAlloc g_Alloc = { SzAlloc, SzFree };
+// static const ISzAlloc g_Alloc_temp = { SzAllocTemp, SzFreeTemp };
+
+
+static void Print(const char *s)
+{
+  fputs(s, stdout);
+}
+
+
+static int Buf_EnsureSize(CBuf *dest, size_t size)
+{
+  if (dest->size >= size)
+    return 1;
+  Buf_Free(dest, &g_Alloc);
+  return Buf_Create(dest, size, &g_Alloc);
+}
+
+#ifndef _WIN32
+#define MY_USE_UTF8
+#endif
+
+/* #define MY_USE_UTF8 */
+
+#ifdef MY_USE_UTF8
+
+#define MY_UTF8_START(n) (0x100 - (1 << (7 - (n))))
+
+#define MY_UTF8_RANGE(n) (((UInt32)1) << ((n) * 5 + 6))
+
+#define MY_UTF8_HEAD(n, val) ((Byte)(MY_UTF8_START(n) + (val >> (6 * (n)))))
+#define MY_UTF8_CHAR(n, val) ((Byte)(0x80 + (((val) >> (6 * (n))) & 0x3F)))
+
+static size_t Utf16_To_Utf8_Calc(const UInt16 *src, const UInt16 *srcLim)
+{
+  size_t size = 0;
+  for (;;)
+  {
+    UInt32 val;
+    if (src == srcLim)
+      return size;
+    
+    size++;
+    val = *src++;
+   
+    if (val < 0x80)
+      continue;
+
+    if (val < MY_UTF8_RANGE(1))
+    {
+      size++;
+      continue;
+    }
+
+    if (val >= 0xD800 && val < 0xDC00 && src != srcLim)
+    {
+      const UInt32 c2 = *src;
+      if (c2 >= 0xDC00 && c2 < 0xE000)
+      {
+        src++;
+        size += 3;
+        continue;
+      }
+    }
+
+    size += 2;
+  }
+}
+
+static Byte *Utf16_To_Utf8(Byte *dest, const UInt16 *src, const UInt16 *srcLim)
+{
+  for (;;)
+  {
+    UInt32 val;
+    if (src == srcLim)
+      return dest;
+    
+    val = *src++;
+    
+    if (val < 0x80)
+    {
+      *dest++ = (Byte)val;
+      continue;
+    }
+
+    if (val < MY_UTF8_RANGE(1))
+    {
+      dest[0] = MY_UTF8_HEAD(1, val);
+      dest[1] = MY_UTF8_CHAR(0, val);
+      dest += 2;
+      continue;
+    }
+
+    if (val >= 0xD800 && val < 0xDC00 && src != srcLim)
+    {
+      const UInt32 c2 = *src;
+      if (c2 >= 0xDC00 && c2 < 0xE000)
+      {
+        src++;
+        val = (((val - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
+        dest[0] = MY_UTF8_HEAD(3, val);
+        dest[1] = MY_UTF8_CHAR(2, val);
+        dest[2] = MY_UTF8_CHAR(1, val);
+        dest[3] = MY_UTF8_CHAR(0, val);
+        dest += 4;
+        continue;
+      }
+    }
+    
+    dest[0] = MY_UTF8_HEAD(2, val);
+    dest[1] = MY_UTF8_CHAR(1, val);
+    dest[2] = MY_UTF8_CHAR(0, val);
+    dest += 3;
+  }
+}
+
+static SRes Utf16_To_Utf8Buf(CBuf *dest, const UInt16 *src, size_t srcLen)
+{
+  size_t destLen = Utf16_To_Utf8_Calc(src, src + srcLen);
+  destLen += 1;
+  if (!Buf_EnsureSize(dest, destLen))
+    return SZ_ERROR_MEM;
+  *Utf16_To_Utf8(dest->data, src, src + srcLen) = 0;
+  return SZ_OK;
+}
+
+#endif
+
+static SRes Utf16_To_Char(CBuf *buf, const UInt16 *s
+    #ifndef MY_USE_UTF8
+    , UINT codePage
+    #endif
+    )
+{
+  size_t len = 0;
+  for (len = 0; s[len] != 0; len++) {}
+
+  #ifndef MY_USE_UTF8
+  {
+    const size_t size = len * 3 + 100;
+    if (!Buf_EnsureSize(buf, size))
+      return SZ_ERROR_MEM;
+    {
+      buf->data[0] = 0;
+      if (len != 0)
+      {
+        const char defaultChar = '_';
+        BOOL defUsed;
+        const unsigned numChars = (unsigned)WideCharToMultiByte(
+            codePage, 0, (LPCWSTR)s, (int)len, (char *)buf->data, (int)size, &defaultChar, &defUsed);
+        if (numChars == 0 || numChars >= size)
+          return SZ_ERROR_FAIL;
+        buf->data[numChars] = 0;
+      }
+      return SZ_OK;
+    }
+  }
+  #else
+  return Utf16_To_Utf8Buf(buf, s, len);
+  #endif
+}
+
+#ifdef _WIN32
+  #ifndef USE_WINDOWS_FILE
+    static UINT g_FileCodePage = CP_ACP;
+    #define MY_FILE_CODE_PAGE_PARAM ,g_FileCodePage
+  #endif
+#else
+  #define MY_FILE_CODE_PAGE_PARAM
+#endif
+
+static WRes MyCreateDir(const UInt16 *name)
+{
+  #ifdef USE_WINDOWS_FILE
+  
+  return CreateDirectoryW((LPCWSTR)name, NULL) ? 0 : GetLastError();
+  
+  #else
+
+  CBuf buf;
+  WRes res;
+  Buf_Init(&buf);
+  RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM))
+
+  res =
+  #ifdef _WIN32
+  _mkdir((const char *)buf.data)
+  #else
+  mkdir((const char *)buf.data, 0777)
+  #endif
+  == 0 ? 0 : errno;
+  Buf_Free(&buf, &g_Alloc);
+  return res;
+  
+  #endif
+}
+
+static WRes OutFile_OpenUtf16(CSzFile *p, const UInt16 *name)
+{
+  #ifdef USE_WINDOWS_FILE
+  return OutFile_OpenW(p, (LPCWSTR)name);
+  #else
+  CBuf buf;
+  WRes res;
+  Buf_Init(&buf);
+  RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM))
+  res = OutFile_Open(p, (const char *)buf.data);
+  Buf_Free(&buf, &g_Alloc);
+  return res;
+  #endif
+}
+
+
+static SRes PrintString(const UInt16 *s)
+{
+  CBuf buf;
+  SRes res;
+  Buf_Init(&buf);
+  res = Utf16_To_Char(&buf, s
+      #ifndef MY_USE_UTF8
+      , CP_OEMCP
+      #endif
+      );
+  if (res == SZ_OK)
+    Print((const char *)buf.data);
+  Buf_Free(&buf, &g_Alloc);
+  return res;
+}
+
+static void UInt64ToStr(UInt64 value, char *s, int numDigits)
+{
+  char temp[32];
+  int pos = 0;
+  do
+  {
+    temp[pos++] = (char)('0' + (unsigned)(value % 10));
+    value /= 10;
+  }
+  while (value != 0);
+
+  for (numDigits -= pos; numDigits > 0; numDigits--)
+    *s++ = ' ';
+
+  do
+    *s++ = temp[--pos];
+  while (pos);
+  *s = '\0';
+}
+
+static char *UIntToStr(char *s, unsigned value, int numDigits)
+{
+  char temp[16];
+  int pos = 0;
+  do
+    temp[pos++] = (char)('0' + (value % 10));
+  while (value /= 10);
+
+  for (numDigits -= pos; numDigits > 0; numDigits--)
+    *s++ = '0';
+
+  do
+    *s++ = temp[--pos];
+  while (pos);
+  *s = '\0';
+  return s;
+}
+
+static void UIntToStr_2(char *s, unsigned value)
+{
+  s[0] = (char)('0' + (value / 10));
+  s[1] = (char)('0' + (value % 10));
+}
+
+
+#define PERIOD_4 (4 * 365 + 1)
+#define PERIOD_100 (PERIOD_4 * 25 - 1)
+#define PERIOD_400 (PERIOD_100 * 4 + 1)
+
+
+
+#ifndef _WIN32
+
+// MS uses long for BOOL, but long is 32-bit in MS. So we use int.
+// typedef long BOOL;
+typedef int BOOL;
+
+typedef struct
+{
+  DWORD dwLowDateTime;
+  DWORD dwHighDateTime;
+} FILETIME;
+
+static LONG TIME_GetBias(void)
+{
+  const time_t utc = time(NULL);
+  struct tm *ptm = localtime(&utc);
+  const int localdaylight = ptm->tm_isdst; /* daylight for local timezone */
+  ptm = gmtime(&utc);
+  ptm->tm_isdst = localdaylight; /* use local daylight, not that of Greenwich */
+  return (int)(mktime(ptm) - utc);
+}
+
+#define TICKS_PER_SEC 10000000
+
+#define GET_TIME_64(pft) ((pft)->dwLowDateTime | ((UInt64)(pft)->dwHighDateTime << 32))
+
+#define SET_FILETIME(ft, v64) \
+   (ft)->dwLowDateTime = (DWORD)v64; \
+   (ft)->dwHighDateTime = (DWORD)(v64 >> 32);
+
+#define WINAPI
+#define TRUE 1
+
+static BOOL WINAPI FileTimeToLocalFileTime(const FILETIME *fileTime, FILETIME *localFileTime)
+{
+  UInt64 v = GET_TIME_64(fileTime);
+  v = (UInt64)((Int64)v - (Int64)TIME_GetBias() * TICKS_PER_SEC);
+  SET_FILETIME(localFileTime, v)
+  return TRUE;
+}
+
+static const UInt32 kNumTimeQuantumsInSecond = 10000000;
+static const UInt32 kFileTimeStartYear = 1601;
+static const UInt32 kUnixTimeStartYear = 1970;
+
+static Int64 Time_FileTimeToUnixTime64(const FILETIME *ft)
+{
+  const UInt64 kUnixTimeOffset =
+      (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear));
+  const UInt64 winTime = GET_TIME_64(ft);
+  return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset;
+}
+
+#if defined(_AIX)
+  #define MY_ST_TIMESPEC st_timespec
+#else
+  #define MY_ST_TIMESPEC timespec
+#endif
+
+static void FILETIME_To_timespec(const FILETIME *ft, struct MY_ST_TIMESPEC *ts)
+{
+  if (ft)
+  {
+    const Int64 sec = Time_FileTimeToUnixTime64(ft);
+    // time_t is long
+    const time_t sec2 = (time_t)sec;
+    if (sec2 == sec)
+    {
+      ts->tv_sec = sec2;
+      {
+        const UInt64 winTime = GET_TIME_64(ft);
+        ts->tv_nsec = (long)((winTime % 10000000) * 100);
+      }
+      return;
+    }
+  }
+  // else
+  {
+    ts->tv_sec = 0;
+    // ts.tv_nsec = UTIME_NOW; // set to the current time
+    ts->tv_nsec = UTIME_OMIT; // keep old timesptamp
+  }
+}
+
+static WRes Set_File_FILETIME(const UInt16 *name, const FILETIME *mTime)
+{
+  struct timespec times[2];
+  
+  const int flags = 0; // follow link
+    // = AT_SYMLINK_NOFOLLOW; // don't follow link
+
+  CBuf buf;
+  int res;
+  Buf_Init(&buf);
+  RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM))
+  FILETIME_To_timespec(NULL, &times[0]);
+  FILETIME_To_timespec(mTime, &times[1]);
+  res = utimensat(AT_FDCWD, (const char *)buf.data, times, flags);
+  Buf_Free(&buf, &g_Alloc);
+  if (res == 0)
+    return 0;
+  return errno;
+}
+
+#endif
+
+static void NtfsFileTime_to_FILETIME(const CNtfsFileTime *t, FILETIME *ft)
+{
+  ft->dwLowDateTime = (DWORD)(t->Low);
+  ft->dwHighDateTime = (DWORD)(t->High);
+}
+
+static void ConvertFileTimeToString(const CNtfsFileTime *nTime, char *s)
+{
+  unsigned year, mon, hour, min, sec;
+  Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+  UInt32 t;
+  UInt32 v;
+  // UInt64 v64 = nt->Low | ((UInt64)nt->High << 32);
+  UInt64 v64;
+  {
+    FILETIME fileTime, locTime;
+    NtfsFileTime_to_FILETIME(nTime, &fileTime);
+    if (!FileTimeToLocalFileTime(&fileTime, &locTime))
+    {
+      locTime.dwHighDateTime =
+      locTime.dwLowDateTime = 0;
+    }
+    v64 = locTime.dwLowDateTime | ((UInt64)locTime.dwHighDateTime << 32);
+  }
+  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;
+
+  t = v / PERIOD_100; if (t ==  4) t =  3; year += t * 100; v -= t * PERIOD_100;
+  t = v / PERIOD_4;   if (t == 25) t = 24; year += t * 4;   v -= t * PERIOD_4;
+  t = v / 365;        if (t ==  4) t =  3; year += t;       v -= t * 365;
+
+  if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
+    ms[1] = 29;
+  for (mon = 0;; mon++)
+  {
+    const UInt32 d = ms[mon];
+    if (v < d)
+      break;
+    v -= d;
+  }
+  s = UIntToStr(s, year, 4); *s++ = '-';
+  UIntToStr_2(s, mon + 1); s[2] = '-'; s += 3;
+  UIntToStr_2(s, (unsigned)v + 1); s[2] = ' '; s += 3;
+  UIntToStr_2(s, hour); s[2] = ':'; s += 3;
+  UIntToStr_2(s, min); s[2] = ':'; s += 3;
+  UIntToStr_2(s, sec); s[2] = 0;
+}
+
+static void PrintLF(void)
+{
+  Print("\n");
+}
+
+static void PrintError(char *s)
+{
+  Print("\nERROR: ");
+  Print(s);
+  PrintLF();
+}
+
+static void PrintError_WRes(const char *message, WRes wres)
+{
+  Print("\nERROR: ");
+  Print(message);
+  PrintLF();
+  {
+    char s[32];
+    UIntToStr(s, (unsigned)wres, 1);
+    Print("System error code: ");
+    Print(s);
+  }
+  // sprintf(buffer + strlen(buffer), "\nSystem error code: %d", (unsigned)wres);
+  #ifdef _WIN32
+  {
+    char *s = NULL;
+    if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+        NULL, wres, 0, (LPSTR) &s, 0, NULL) != 0 && s)
+    {
+      Print(" : ");
+      Print(s);
+      LocalFree(s);
+    }
+  }
+  #else
+  {
+    const char *s = strerror(wres);
+    if (s)
+    {
+      Print(" : ");
+      Print(s);
+    }
+  }
+  #endif
+  PrintLF();
+}
+
+static void GetAttribString(UInt32 wa, BoolInt isDir, char *s)
+{
+  #ifdef USE_WINDOWS_FILE
+  s[0] = (char)(((wa & FILE_ATTRIBUTE_DIRECTORY) != 0 || isDir) ? 'D' : '.');
+  s[1] = (char)(((wa & FILE_ATTRIBUTE_READONLY ) != 0) ? 'R': '.');
+  s[2] = (char)(((wa & FILE_ATTRIBUTE_HIDDEN   ) != 0) ? 'H': '.');
+  s[3] = (char)(((wa & FILE_ATTRIBUTE_SYSTEM   ) != 0) ? 'S': '.');
+  s[4] = (char)(((wa & FILE_ATTRIBUTE_ARCHIVE  ) != 0) ? 'A': '.');
+  s[5] = 0;
+  #else
+  s[0] = (char)(((wa & (1 << 4)) != 0 || isDir) ? 'D' : '.');
+  s[1] = 0;
+  #endif
+}
+
+
+// #define NUM_PARENTS_MAX 128
+
+int Z7_CDECL main(int numargs, char *args[])
+{
+  ISzAlloc allocImp;
+  ISzAlloc allocTempImp;
+
+  CFileInStream archiveStream;
+  CLookToRead2 lookStream;
+  CSzArEx db;
+  SRes res;
+  UInt16 *temp = NULL;
+  size_t tempSize = 0;
+  // UInt32 parents[NUM_PARENTS_MAX];
+
+  Print("\n7z Decoder " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n");
+
+  if (numargs == 1)
+  {
+    Print(
+      "Usage: 7zDec <command> <archive_name>\n\n"
+      "<Commands>\n"
+      "  e: Extract files from archive (without using directory names)\n"
+      "  l: List contents of archive\n"
+      "  t: Test integrity of archive\n"
+      "  x: eXtract files with full paths\n");
+    return 0;
+  }
+
+  if (numargs < 3)
+  {
+    PrintError("incorrect command");
+    return 1;
+  }
+
+  #if defined(_WIN32) && !defined(USE_WINDOWS_FILE) && !defined(UNDER_CE)
+  g_FileCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
+  #endif
+
+
+  allocImp = g_Alloc;
+  allocTempImp = g_Alloc;
+  // allocTempImp = g_Alloc_temp;
+
+  {
+    WRes wres =
+    #ifdef UNDER_CE
+      InFile_OpenW(&archiveStream.file, L"\test.7z"); // change it
+    #else
+      InFile_Open(&archiveStream.file, args[2]);
+    #endif
+    if (wres != 0)
+    {
+      PrintError_WRes("cannot open input file", wres);
+      return 1;
+    }
+  }
+
+  FileInStream_CreateVTable(&archiveStream);
+  archiveStream.wres = 0;
+  LookToRead2_CreateVTable(&lookStream, False);
+  lookStream.buf = NULL;
+
+  res = SZ_OK;
+
+  {
+    lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize);
+    if (!lookStream.buf)
+      res = SZ_ERROR_MEM;
+    else
+    {
+      lookStream.bufSize = kInputBufSize;
+      lookStream.realStream = &archiveStream.vt;
+      LookToRead2_INIT(&lookStream)
+    }
+  }
+    
+  CrcGenerateTable();
+    
+  SzArEx_Init(&db);
+    
+  if (res == SZ_OK)
+  {
+    res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp);
+  }
+  
+  if (res == SZ_OK)
+  {
+    char *command = args[1];
+    int listCommand = 0, testCommand = 0, fullPaths = 0;
+    
+    if (strcmp(command, "l") == 0) listCommand = 1;
+    else if (strcmp(command, "t") == 0) testCommand = 1;
+    else if (strcmp(command, "e") == 0) { }
+    else if (strcmp(command, "x") == 0) { fullPaths = 1; }
+    else
+    {
+      PrintError("incorrect command");
+      res = SZ_ERROR_FAIL;
+    }
+
+    if (res == SZ_OK)
+    {
+      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) */
+
+      for (i = 0; i < db.NumFiles; i++)
+      {
+        size_t offset = 0;
+        size_t outSizeProcessed = 0;
+        // const CSzFileItem *f = db.Files + i;
+        size_t len;
+        const BoolInt isDir = SzArEx_IsDir(&db, i);
+        if (listCommand == 0 && isDir && !fullPaths)
+          continue;
+        len = SzArEx_GetFileNameUtf16(&db, i, NULL);
+        // len = SzArEx_GetFullNameLen(&db, i);
+
+        if (len > tempSize)
+        {
+          SzFree(NULL, temp);
+          tempSize = len;
+          temp = (UInt16 *)SzAlloc(NULL, tempSize * sizeof(temp[0]));
+          if (!temp)
+          {
+            res = SZ_ERROR_MEM;
+            break;
+          }
+        }
+
+        SzArEx_GetFileNameUtf16(&db, i, temp);
+        /*
+        if (SzArEx_GetFullNameUtf16_Back(&db, i, temp + len) != temp)
+        {
+          res = SZ_ERROR_FAIL;
+          break;
+        }
+        */
+
+        if (listCommand)
+        {
+          char attr[8], s[32], t[32];
+          UInt64 fileSize;
+
+          GetAttribString(SzBitWithVals_Check(&db.Attribs, i) ? db.Attribs.Vals[i] : 0, isDir, attr);
+
+          fileSize = SzArEx_GetFileSize(&db, i);
+          UInt64ToStr(fileSize, s, 10);
+          
+          if (SzBitWithVals_Check(&db.MTime, i))
+            ConvertFileTimeToString(&db.MTime.Vals[i], t);
+          else
+          {
+            size_t j;
+            for (j = 0; j < 19; j++)
+              t[j] = ' ';
+            t[j] = '\0';
+          }
+          
+          Print(t);
+          Print(" ");
+          Print(attr);
+          Print(" ");
+          Print(s);
+          Print("  ");
+          res = PrintString(temp);
+          if (res != SZ_OK)
+            break;
+          if (isDir)
+            Print("/");
+          PrintLF();
+          continue;
+        }
+
+        Print(testCommand ?
+            "T ":
+            "- ");
+        res = PrintString(temp);
+        if (res != SZ_OK)
+          break;
+        
+        if (isDir)
+          Print("/");
+        else
+        {
+          res = SzArEx_Extract(&db, &lookStream.vt, i,
+              &blockIndex, &outBuffer, &outBufferSize,
+              &offset, &outSizeProcessed,
+              &allocImp, &allocTempImp);
+          if (res != SZ_OK)
+            break;
+        }
+        
+        if (!testCommand)
+        {
+          CSzFile outFile;
+          size_t processedSize;
+          size_t j;
+          UInt16 *name = (UInt16 *)temp;
+          const UInt16 *destPath = (const UInt16 *)name;
+ 
+          for (j = 0; name[j] != 0; j++)
+            if (name[j] == '/')
+            {
+              if (fullPaths)
+              {
+                name[j] = 0;
+                MyCreateDir(name);
+                name[j] = CHAR_PATH_SEPARATOR;
+              }
+              else
+                destPath = name + j + 1;
+            }
+    
+          if (isDir)
+          {
+            MyCreateDir(destPath);
+            PrintLF();
+            continue;
+          }
+          else
+          {
+            const WRes wres = OutFile_OpenUtf16(&outFile, destPath);
+            if (wres != 0)
+            {
+              PrintError_WRes("cannot open output file", wres);
+              res = SZ_ERROR_FAIL;
+              break;
+            }
+          }
+
+          processedSize = outSizeProcessed;
+          
+          {
+            const WRes wres = File_Write(&outFile, outBuffer + offset, &processedSize);
+            if (wres != 0 || processedSize != outSizeProcessed)
+            {
+              PrintError_WRes("cannot write output file", wres);
+              res = SZ_ERROR_FAIL;
+              break;
+            }
+          }
+
+          {
+            FILETIME mtime;
+            FILETIME *mtimePtr = NULL;
+            
+            #ifdef USE_WINDOWS_FILE
+            FILETIME ctime;
+            FILETIME *ctimePtr = NULL;
+            #endif
+
+            if (SzBitWithVals_Check(&db.MTime, i))
+            {
+              const CNtfsFileTime *t = &db.MTime.Vals[i];
+              mtime.dwLowDateTime = (DWORD)(t->Low);
+              mtime.dwHighDateTime = (DWORD)(t->High);
+              mtimePtr = &mtime;
+            }
+
+            #ifdef USE_WINDOWS_FILE
+            if (SzBitWithVals_Check(&db.CTime, i))
+            {
+              const CNtfsFileTime *t = &db.CTime.Vals[i];
+              ctime.dwLowDateTime = (DWORD)(t->Low);
+              ctime.dwHighDateTime = (DWORD)(t->High);
+              ctimePtr = &ctime;
+            }
+
+            if (mtimePtr || ctimePtr)
+              SetFileTime(outFile.handle, ctimePtr, NULL, mtimePtr);
+            #endif
+          
+            {
+              const WRes wres = File_Close(&outFile);
+              if (wres != 0)
+              {
+                PrintError_WRes("cannot close output file", wres);
+                res = SZ_ERROR_FAIL;
+                break;
+              }
+            }
+
+            #ifndef USE_WINDOWS_FILE
+            #ifdef _WIN32
+            mtimePtr = mtimePtr;
+            #else
+            if (mtimePtr)
+              Set_File_FILETIME(destPath, mtimePtr);
+            #endif
+            #endif
+          }
+          
+          #ifdef USE_WINDOWS_FILE
+          if (SzBitWithVals_Check(&db.Attribs, i))
+          {
+            UInt32 attrib = db.Attribs.Vals[i];
+            /* p7zip stores posix attributes in high 16 bits and adds 0x8000 as marker.
+               We remove posix bits, if we detect posix mode field */
+            if ((attrib & 0xF0000000) != 0)
+              attrib &= 0x7FFF;
+            SetFileAttributesW((LPCWSTR)destPath, attrib);
+          }
+          #endif
+        }
+        PrintLF();
+      }
+      ISzAlloc_Free(&allocImp, outBuffer);
+    }
+  }
+
+  SzFree(NULL, temp);
+  SzArEx_Free(&db, &allocImp);
+  ISzAlloc_Free(&allocImp, lookStream.buf);
+
+  File_Close(&archiveStream.file);
+  
+  if (res == SZ_OK)
+  {
+    Print("\nEverything is Ok\n");
+    return 0;
+  }
+  
+  if (res == SZ_ERROR_UNSUPPORTED)
+    PrintError("decoder doesn't support this archive");
+  else if (res == SZ_ERROR_MEM)
+    PrintError("cannot allocate memory");
+  else if (res == SZ_ERROR_CRC)
+    PrintError("CRC error");
+  else if (res == SZ_ERROR_READ /* || archiveStream.Res != 0 */)
+    PrintError_WRes("Read Error", archiveStream.wres);
+  else
+  {
+    char s[32];
+    UInt64ToStr((unsigned)res, s, 0);
+    PrintError(s);
+  }
+  
+  return 1;
+}

+ 4 - 0
Components/Lzma2/Util/7z/Precomp.c

@@ -0,0 +1,4 @@
+/* Precomp.c -- StdAfx
+2013-01-21 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"

+ 13 - 0
Components/Lzma2/Util/7z/Precomp.h

@@ -0,0 +1,13 @@
+/* Precomp.h -- Precomp
+2024-01-23 : Igor Pavlov : Public domain */
+
+// #ifndef ZIP7_INC_PRECOMP_LOC_H
+// #define ZIP7_INC_PRECOMP_LOC_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+
+#include "../../Precomp.h"
+
+// #endif