1baa3858d3f5d128a5c8466b700098109edcad5f2repo sync/* XzIn.c - Xz input
2cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky2014-12-30 : Igor Pavlov : Public domain */
3cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky
4cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky#include "Precomp.h"
5baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
6baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#include <string.h>
7baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
8baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#include "7zCrc.h"
9baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#include "CpuArch.h"
10baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#include "Xz.h"
11baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
12baa3858d3f5d128a5c8466b700098109edcad5f2repo syncSRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream)
13baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
14baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  Byte sig[XZ_STREAM_HEADER_SIZE];
15baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  RINOK(SeqInStream_Read2(inStream, sig, XZ_STREAM_HEADER_SIZE, SZ_ERROR_NO_ARCHIVE));
16baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0)
17baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_ERROR_NO_ARCHIVE;
18baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return Xz_ParseHeader(p, sig);
19baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
20baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
21baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define READ_VARINT_AND_CHECK(buf, pos, size, res) \
22baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \
23baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; }
24baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
25baa3858d3f5d128a5c8466b700098109edcad5f2repo syncSRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, Bool *isIndex, UInt32 *headerSizeRes)
26baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
27baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
28baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  unsigned headerSize;
29baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  *headerSizeRes = 0;
30baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  RINOK(SeqInStream_ReadByte(inStream, &header[0]));
31baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  headerSize = ((unsigned)header[0] << 2) + 4;
32baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (headerSize == 0)
33baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
34baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    *headerSizeRes = 1;
35baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    *isIndex = True;
36baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_OK;
37baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
38baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
39baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  *isIndex = False;
40baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  *headerSizeRes = headerSize;
41baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  RINOK(SeqInStream_Read(inStream, header + 1, headerSize - 1));
42baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return XzBlock_Parse(p, header);
43baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
44baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
45baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define ADD_SIZE_CHECH(size, val) \
46baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  { UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; }
47baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
48baa3858d3f5d128a5c8466b700098109edcad5f2repo syncUInt64 Xz_GetUnpackSize(const CXzStream *p)
49baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
50baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  UInt64 size = 0;
51baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  size_t i;
52baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  for (i = 0; i < p->numBlocks; i++)
53baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    ADD_SIZE_CHECH(size, p->blocks[i].unpackSize);
54baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return size;
55baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
56baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
57baa3858d3f5d128a5c8466b700098109edcad5f2repo syncUInt64 Xz_GetPackSize(const CXzStream *p)
58baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
59baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  UInt64 size = 0;
60baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  size_t i;
61baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  for (i = 0; i < p->numBlocks; i++)
62baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    ADD_SIZE_CHECH(size, (p->blocks[i].totalSize + 3) & ~(UInt64)3);
63baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return size;
64baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
65baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
66baa3858d3f5d128a5c8466b700098109edcad5f2repo sync/*
67baa3858d3f5d128a5c8466b700098109edcad5f2repo syncSRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStream *inStream)
68baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
69baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f));
70baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
71baa3858d3f5d128a5c8466b700098109edcad5f2repo sync*/
72baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
73baa3858d3f5d128a5c8466b700098109edcad5f2repo syncstatic SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAlloc *alloc)
74baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
75cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky  size_t i, numBlocks, pos = 1;
76baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  UInt32 crc;
77baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
78baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (size < 5 || buf[0] != 0)
79baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_ERROR_ARCHIVE;
80baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
81baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  size -= 4;
82baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  crc = CrcCalc(buf, size);
83baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (crc != GetUi32(buf + size))
84baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_ERROR_ARCHIVE;
85baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
86baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
87baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    UInt64 numBlocks64;
88baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64);
89baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    numBlocks = (size_t)numBlocks64;
90baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    if (numBlocks != numBlocks64 || numBlocks * 2 > size)
91baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      return SZ_ERROR_ARCHIVE;
92baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
93baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
94baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  Xz_Free(p, alloc);
95baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (numBlocks != 0)
96baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
97baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    p->numBlocks = numBlocks;
98baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    p->numBlocksAllocated = numBlocks;
99baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    p->blocks = alloc->Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks);
100baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    if (p->blocks == 0)
101baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      return SZ_ERROR_MEM;
102baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    for (i = 0; i < numBlocks; i++)
103baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    {
104baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      CXzBlockSizes *block = &p->blocks[i];
105baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize);
106baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize);
107baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      if (block->totalSize == 0)
108baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        return SZ_ERROR_ARCHIVE;
109baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    }
110baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
111baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  while ((pos & 3) != 0)
112baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    if (buf[pos++] != 0)
113baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      return SZ_ERROR_ARCHIVE;
114baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
115baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
116baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
117baa3858d3f5d128a5c8466b700098109edcad5f2repo syncstatic SRes Xz_ReadIndex(CXzStream *p, ILookInStream *stream, UInt64 indexSize, ISzAlloc *alloc)
118baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
119baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  SRes res;
120baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  size_t size;
121baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  Byte *buf;
122baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (indexSize > ((UInt32)1 << 31))
123baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_ERROR_UNSUPPORTED;
124baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  size = (size_t)indexSize;
125baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (size != indexSize)
126baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_ERROR_UNSUPPORTED;
127baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  buf = alloc->Alloc(alloc, size);
128baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (buf == 0)
129baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_ERROR_MEM;
130baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED);
131baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (res == SZ_OK)
132baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    res = Xz_ReadIndex2(p, buf, size, alloc);
133baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  alloc->Free(alloc, buf);
134baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return res;
135baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
136baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
137baa3858d3f5d128a5c8466b700098109edcad5f2repo syncstatic SRes SeekFromCur(ILookInStream *inStream, Int64 *res)
138baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
139baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return inStream->Seek(inStream, res, SZ_SEEK_CUR);
140baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
141baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
142baa3858d3f5d128a5c8466b700098109edcad5f2repo syncstatic SRes Xz_ReadBackward(CXzStream *p, ILookInStream *stream, Int64 *startOffset, ISzAlloc *alloc)
143baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
144baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  UInt64 indexSize;
145baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  Byte buf[XZ_STREAM_FOOTER_SIZE];
146baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
147baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if ((*startOffset & 3) != 0 || *startOffset < XZ_STREAM_FOOTER_SIZE)
148baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_ERROR_NO_ARCHIVE;
149baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  *startOffset = -XZ_STREAM_FOOTER_SIZE;
150baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  RINOK(SeekFromCur(stream, startOffset));
151baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
152baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE));
153baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
154baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0)
155baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
156cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky    UInt32 total = 0;
157baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    *startOffset += XZ_STREAM_FOOTER_SIZE;
158baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    for (;;)
159baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    {
160cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky      size_t i;
161baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      #define TEMP_BUF_SIZE (1 << 10)
162baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      Byte tempBuf[TEMP_BUF_SIZE];
163cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky      if (*startOffset < XZ_STREAM_FOOTER_SIZE || total > (1 << 16))
164baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        return SZ_ERROR_NO_ARCHIVE;
165cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky      i = (*startOffset > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)*startOffset;
166cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky      total += (UInt32)i;
167cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky      *startOffset = -(Int64)i;
168baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      RINOK(SeekFromCur(stream, startOffset));
169cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky      RINOK(LookInStream_Read2(stream, tempBuf, i, SZ_ERROR_NO_ARCHIVE));
170cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky      for (; i != 0; i--)
171cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky        if (tempBuf[i - 1] != 0)
172baa3858d3f5d128a5c8466b700098109edcad5f2repo sync          break;
173cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky      if (i != 0)
174baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      {
175cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky        if ((i & 3) != 0)
176baa3858d3f5d128a5c8466b700098109edcad5f2repo sync          return SZ_ERROR_NO_ARCHIVE;
177cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky        *startOffset += i;
178baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        break;
179baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      }
180baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    }
181cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky    if (*startOffset < XZ_STREAM_FOOTER_SIZE)
182cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky      return SZ_ERROR_NO_ARCHIVE;
183cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky    *startOffset -= XZ_STREAM_FOOTER_SIZE;
184cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky    RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET));
185cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky    RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE));
186cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky    if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0)
187cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky      return SZ_ERROR_NO_ARCHIVE;
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;
294cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky      if (p->num != 0)
295cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky        memcpy(data, p->streams, p->num * sizeof(CXzStream));
296baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      alloc->Free(alloc, p->streams);
297baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      p->streams = (CXzStream *)data;
298baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    }
299baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    p->streams[p->num++] = st;
300baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    if (*startOffset == 0)
301baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      break;
302baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET));
303baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    if (progress && progress->Progress(progress, endOffset - *startOffset, (UInt64)(Int64)-1) != SZ_OK)
304baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      return SZ_ERROR_PROGRESS;
305baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
306baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return SZ_OK;
307baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
308