1baa3858d3f5d128a5c8466b700098109edcad5f2repo sync/* XzIn.c - Xz input
2baa3858d3f5d128a5c8466b700098109edcad5f2repo sync2009-06-19 : Igor Pavlov : Public domain */
3baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
4baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#include <string.h>
5baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
6baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#include "7zCrc.h"
7baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#include "CpuArch.h"
8baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#include "Xz.h"
9baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
10baa3858d3f5d128a5c8466b700098109edcad5f2repo syncSRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream)
11baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
12baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  Byte sig[XZ_STREAM_HEADER_SIZE];
13baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  RINOK(SeqInStream_Read2(inStream, sig, XZ_STREAM_HEADER_SIZE, SZ_ERROR_NO_ARCHIVE));
14baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0)
15baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_ERROR_NO_ARCHIVE;
16baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return Xz_ParseHeader(p, sig);
17baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
18baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
19baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define READ_VARINT_AND_CHECK(buf, pos, size, res) \
20baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \
21baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; }
22baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
23baa3858d3f5d128a5c8466b700098109edcad5f2repo syncSRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, Bool *isIndex, UInt32 *headerSizeRes)
24baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
25baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
26baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  unsigned headerSize;
27baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  *headerSizeRes = 0;
28baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  RINOK(SeqInStream_ReadByte(inStream, &header[0]));
29baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  headerSize = ((unsigned)header[0] << 2) + 4;
30baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (headerSize == 0)
31baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
32baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    *headerSizeRes = 1;
33baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    *isIndex = True;
34baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_OK;
35baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
36baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
37baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  *isIndex = False;
38baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  *headerSizeRes = headerSize;
39baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  RINOK(SeqInStream_Read(inStream, header + 1, headerSize - 1));
40baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return XzBlock_Parse(p, header);
41baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
42baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
43baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define ADD_SIZE_CHECH(size, val) \
44baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  { UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; }
45baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
46baa3858d3f5d128a5c8466b700098109edcad5f2repo syncUInt64 Xz_GetUnpackSize(const CXzStream *p)
47baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
48baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  UInt64 size = 0;
49baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  size_t i;
50baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  for (i = 0; i < p->numBlocks; i++)
51baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    ADD_SIZE_CHECH(size, p->blocks[i].unpackSize);
52baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return size;
53baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
54baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
55baa3858d3f5d128a5c8466b700098109edcad5f2repo syncUInt64 Xz_GetPackSize(const CXzStream *p)
56baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
57baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  UInt64 size = 0;
58baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  size_t i;
59baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  for (i = 0; i < p->numBlocks; i++)
60baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    ADD_SIZE_CHECH(size, (p->blocks[i].totalSize + 3) & ~(UInt64)3);
61baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return size;
62baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
63baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
64baa3858d3f5d128a5c8466b700098109edcad5f2repo sync/*
65baa3858d3f5d128a5c8466b700098109edcad5f2repo syncSRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStream *inStream)
66baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
67baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f));
68baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
69baa3858d3f5d128a5c8466b700098109edcad5f2repo sync*/
70baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
71baa3858d3f5d128a5c8466b700098109edcad5f2repo syncstatic SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAlloc *alloc)
72baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
73baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  size_t i, numBlocks, crcStartPos, pos = 1;
74baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  UInt32 crc;
75baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
76baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (size < 5 || buf[0] != 0)
77baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_ERROR_ARCHIVE;
78baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
79baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  size -= 4;
80baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  crc = CrcCalc(buf, size);
81baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (crc != GetUi32(buf + size))
82baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_ERROR_ARCHIVE;
83baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
84baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
85baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    UInt64 numBlocks64;
86baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64);
87baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    numBlocks = (size_t)numBlocks64;
88baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    if (numBlocks != numBlocks64 || numBlocks * 2 > size)
89baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      return SZ_ERROR_ARCHIVE;
90baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
91baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
92baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  crcStartPos = pos;
93baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  Xz_Free(p, alloc);
94baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (numBlocks != 0)
95baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
96baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    p->numBlocks = numBlocks;
97baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    p->numBlocksAllocated = numBlocks;
98baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    p->blocks = alloc->Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks);
99baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    if (p->blocks == 0)
100baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      return SZ_ERROR_MEM;
101baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    for (i = 0; i < numBlocks; i++)
102baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    {
103baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      CXzBlockSizes *block = &p->blocks[i];
104baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize);
105baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize);
106baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      if (block->totalSize == 0)
107baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        return SZ_ERROR_ARCHIVE;
108baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    }
109baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
110baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  while ((pos & 3) != 0)
111baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    if (buf[pos++] != 0)
112baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      return SZ_ERROR_ARCHIVE;
113baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
114baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
115baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
116baa3858d3f5d128a5c8466b700098109edcad5f2repo syncstatic SRes Xz_ReadIndex(CXzStream *p, ILookInStream *stream, UInt64 indexSize, ISzAlloc *alloc)
117baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
118baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  SRes res;
119baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  size_t size;
120baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  Byte *buf;
121baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (indexSize > ((UInt32)1 << 31))
122baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_ERROR_UNSUPPORTED;
123baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  size = (size_t)indexSize;
124baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (size != indexSize)
125baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_ERROR_UNSUPPORTED;
126baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  buf = alloc->Alloc(alloc, size);
127baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (buf == 0)
128baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_ERROR_MEM;
129baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED);
130baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (res == SZ_OK)
131baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    res = Xz_ReadIndex2(p, buf, size, alloc);
132baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  alloc->Free(alloc, buf);
133baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return res;
134baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
135baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
136baa3858d3f5d128a5c8466b700098109edcad5f2repo syncstatic SRes SeekFromCur(ILookInStream *inStream, Int64 *res)
137baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
138baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return inStream->Seek(inStream, res, SZ_SEEK_CUR);
139baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
140baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
141baa3858d3f5d128a5c8466b700098109edcad5f2repo syncstatic SRes Xz_ReadBackward(CXzStream *p, ILookInStream *stream, Int64 *startOffset, ISzAlloc *alloc)
142baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
143baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  UInt64 indexSize;
144baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  Byte buf[XZ_STREAM_FOOTER_SIZE];
145baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
146baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if ((*startOffset & 3) != 0 || *startOffset < XZ_STREAM_FOOTER_SIZE)
147baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_ERROR_NO_ARCHIVE;
148baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  *startOffset = -XZ_STREAM_FOOTER_SIZE;
149baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  RINOK(SeekFromCur(stream, startOffset));
150baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
151baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE));
152baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
153baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0)
154baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
155baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    Int64 i = 0;
156baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    *startOffset += XZ_STREAM_FOOTER_SIZE;
157baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    for (;;)
158baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    {
159baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      int j;
160baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      size_t processedSize;
161baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      #define TEMP_BUF_SIZE (1 << 10)
162baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      Byte tempBuf[TEMP_BUF_SIZE];
163baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      if (*startOffset < XZ_STREAM_FOOTER_SIZE || i > (1 << 16))
164baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        return SZ_ERROR_NO_ARCHIVE;
165baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      processedSize = (*startOffset > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)*startOffset;
166baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      i += processedSize;
167baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      *startOffset = -(Int64)processedSize;
168baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      RINOK(SeekFromCur(stream, startOffset));
169baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      RINOK(LookInStream_Read2(stream, tempBuf, processedSize, SZ_ERROR_NO_ARCHIVE));
170baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      for (j = (int)processedSize; j >= 0; j--)
171baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        if (tempBuf[j -1] != 0)
172baa3858d3f5d128a5c8466b700098109edcad5f2repo sync          break;
173baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      if (j != 0)
174baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      {
175baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        if ((j & 3) != 0)
176baa3858d3f5d128a5c8466b700098109edcad5f2repo sync          return SZ_ERROR_NO_ARCHIVE;
177baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        *startOffset += j;
178baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        if (*startOffset < XZ_STREAM_FOOTER_SIZE)
179baa3858d3f5d128a5c8466b700098109edcad5f2repo sync          return SZ_ERROR_NO_ARCHIVE;
180baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        *startOffset -= XZ_STREAM_FOOTER_SIZE;
181baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET));
182baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE));
183baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0)
184baa3858d3f5d128a5c8466b700098109edcad5f2repo sync          return SZ_ERROR_NO_ARCHIVE;
185baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        break;
186baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      }
187baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    }
188baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
189baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
190baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  p->flags = (CXzStreamFlags)GetBe16(buf + 8);
191baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
192baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (!XzFlags_IsSupported(p->flags))
193baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_ERROR_UNSUPPORTED;
194baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
195baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (GetUi32(buf) != CrcCalc(buf + 4, 6))
196baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_ERROR_ARCHIVE;
197baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
198baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2;
199baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
200baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  *startOffset = -(Int64)(indexSize + XZ_STREAM_FOOTER_SIZE);
201baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  RINOK(SeekFromCur(stream, startOffset));
202baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
203baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  RINOK(Xz_ReadIndex(p, stream, indexSize, alloc));
204baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
205baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
206baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    UInt64 totalSize = Xz_GetPackSize(p);
207baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    UInt64 sum = XZ_STREAM_HEADER_SIZE + totalSize + indexSize;
208baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    if (totalSize == XZ_SIZE_OVERFLOW ||
209baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      sum >= ((UInt64)1 << 63) ||
210baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      totalSize >= ((UInt64)1 << 63))
211baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      return SZ_ERROR_ARCHIVE;
212baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    *startOffset = -(Int64)sum;
213baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    RINOK(SeekFromCur(stream, startOffset));
214baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
215baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
216baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    CXzStreamFlags headerFlags;
217baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    CSecToRead secToRead;
218baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    SecToRead_CreateVTable(&secToRead);
219baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    secToRead.realStream = stream;
220baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
221baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    RINOK(Xz_ReadHeader(&headerFlags, &secToRead.s));
222baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE;
223baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
224baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
225baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
226baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
227baa3858d3f5d128a5c8466b700098109edcad5f2repo sync/* ---------- Xz Streams ---------- */
228baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
229baa3858d3f5d128a5c8466b700098109edcad5f2repo syncvoid Xzs_Construct(CXzs *p)
230baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
231baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  p->num = p->numAllocated = 0;
232baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  p->streams = 0;
233baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
234baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
235baa3858d3f5d128a5c8466b700098109edcad5f2repo syncvoid Xzs_Free(CXzs *p, ISzAlloc *alloc)
236baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
237baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  size_t i;
238baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  for (i = 0; i < p->num; i++)
239baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    Xz_Free(&p->streams[i], alloc);
240baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  alloc->Free(alloc, p->streams);
241baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  p->num = p->numAllocated = 0;
242baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  p->streams = 0;
243baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
244baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
245baa3858d3f5d128a5c8466b700098109edcad5f2repo syncUInt64 Xzs_GetNumBlocks(const CXzs *p)
246baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
247baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  UInt64 num = 0;
248baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  size_t i;
249baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  for (i = 0; i < p->num; i++)
250baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    num += p->streams[i].numBlocks;
251baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return num;
252baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
253baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
254baa3858d3f5d128a5c8466b700098109edcad5f2repo syncUInt64 Xzs_GetUnpackSize(const CXzs *p)
255baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
256baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  UInt64 size = 0;
257baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  size_t i;
258baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  for (i = 0; i < p->num; i++)
259baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    ADD_SIZE_CHECH(size, Xz_GetUnpackSize(&p->streams[i]));
260baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return size;
261baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
262baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
263baa3858d3f5d128a5c8466b700098109edcad5f2repo sync/*
264baa3858d3f5d128a5c8466b700098109edcad5f2repo syncUInt64 Xzs_GetPackSize(const CXzs *p)
265baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
266baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  UInt64 size = 0;
267baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  size_t i;
268baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  for (i = 0; i < p->num; i++)
269baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    ADD_SIZE_CHECH(size, Xz_GetTotalSize(&p->streams[i]));
270baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return size;
271baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
272baa3858d3f5d128a5c8466b700098109edcad5f2repo sync*/
273baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
274baa3858d3f5d128a5c8466b700098109edcad5f2repo syncSRes Xzs_ReadBackward(CXzs *p, ILookInStream *stream, Int64 *startOffset, ICompressProgress *progress, ISzAlloc *alloc)
275baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
276baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  Int64 endOffset = 0;
277baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  RINOK(stream->Seek(stream, &endOffset, SZ_SEEK_END));
278baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  *startOffset = endOffset;
279baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  for (;;)
280baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
281baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    CXzStream st;
282baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    SRes res;
283baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    Xz_Construct(&st);
284baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    res = Xz_ReadBackward(&st, stream, startOffset, alloc);
285baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    st.startOffset = *startOffset;
286baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    RINOK(res);
287baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    if (p->num == p->numAllocated)
288baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    {
289baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      size_t newNum = p->num + p->num / 4 + 1;
290baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      Byte *data = (Byte *)alloc->Alloc(alloc, newNum * sizeof(CXzStream));
291baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      if (data == 0)
292baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        return SZ_ERROR_MEM;
293baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      p->numAllocated = newNum;
294baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      memcpy(data, p->streams, p->num * sizeof(CXzStream));
295baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      alloc->Free(alloc, p->streams);
296baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      p->streams = (CXzStream *)data;
297baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    }
298baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    p->streams[p->num++] = st;
299baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    if (*startOffset == 0)
300baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      break;
301baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET));
302baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    if (progress && progress->Progress(progress, endOffset - *startOffset, (UInt64)(Int64)-1) != SZ_OK)
303baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      return SZ_ERROR_PROGRESS;
304baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
305baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return SZ_OK;
306baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
307