Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5728 serge 1
/* 7zDec.c -- Decoding from 7z folder
2
2015-08-01 : Igor Pavlov : Public domain */
3
 
4
#include "Precomp.h"
5
 
6
#include 
7
 
8
/* #define _7ZIP_PPMD_SUPPPORT */
9
 
10
#include "7z.h"
11
 
12
#include "Bcj2.h"
13
#include "Bra.h"
14
#include "CpuArch.h"
15
#include "Delta.h"
16
#include "LzmaDec.h"
17
#include "Lzma2Dec.h"
18
#ifdef _7ZIP_PPMD_SUPPPORT
19
#include "Ppmd7.h"
20
#endif
21
 
22
#define k_Copy 0
23
#define k_Delta 3
24
#define k_LZMA2 0x21
25
#define k_LZMA  0x30101
26
#define k_BCJ   0x3030103
27
#define k_BCJ2  0x303011B
28
#define k_PPC   0x3030205
29
#define k_IA64  0x3030401
30
#define k_ARM   0x3030501
31
#define k_ARMT  0x3030701
32
#define k_SPARC 0x3030805
33
 
34
 
35
#ifdef _7ZIP_PPMD_SUPPPORT
36
 
37
#define k_PPMD 0x30401
38
 
39
typedef struct
40
{
41
  IByteIn p;
42
  const Byte *cur;
43
  const Byte *end;
44
  const Byte *begin;
45
  UInt64 processed;
46
  Bool extra;
47
  SRes res;
48
  ILookInStream *inStream;
49
} CByteInToLook;
50
 
51
static Byte ReadByte(void *pp)
52
{
53
  CByteInToLook *p = (CByteInToLook *)pp;
54
  if (p->cur != p->end)
55
    return *p->cur++;
56
  if (p->res == SZ_OK)
57
  {
58
    size_t size = p->cur - p->begin;
59
    p->processed += size;
60
    p->res = p->inStream->Skip(p->inStream, size);
61
    size = (1 << 25);
62
    p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size);
63
    p->cur = p->begin;
64
    p->end = p->begin + size;
65
    if (size != 0)
66
      return *p->cur++;;
67
  }
68
  p->extra = True;
69
  return 0;
70
}
71
 
72
static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
73
    Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
74
{
75
  CPpmd7 ppmd;
76
  CByteInToLook s;
77
  SRes res = SZ_OK;
78
 
79
  s.p.Read = ReadByte;
80
  s.inStream = inStream;
81
  s.begin = s.end = s.cur = NULL;
82
  s.extra = False;
83
  s.res = SZ_OK;
84
  s.processed = 0;
85
 
86
  if (propsSize != 5)
87
    return SZ_ERROR_UNSUPPORTED;
88
 
89
  {
90
    unsigned order = props[0];
91
    UInt32 memSize = GetUi32(props + 1);
92
    if (order < PPMD7_MIN_ORDER ||
93
        order > PPMD7_MAX_ORDER ||
94
        memSize < PPMD7_MIN_MEM_SIZE ||
95
        memSize > PPMD7_MAX_MEM_SIZE)
96
      return SZ_ERROR_UNSUPPORTED;
97
    Ppmd7_Construct(&ppmd);
98
    if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
99
      return SZ_ERROR_MEM;
100
    Ppmd7_Init(&ppmd, order);
101
  }
102
  {
103
    CPpmd7z_RangeDec rc;
104
    Ppmd7z_RangeDec_CreateVTable(&rc);
105
    rc.Stream = &s.p;
106
    if (!Ppmd7z_RangeDec_Init(&rc))
107
      res = SZ_ERROR_DATA;
108
    else if (s.extra)
109
      res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
110
    else
111
    {
112
      SizeT i;
113
      for (i = 0; i < outSize; i++)
114
      {
115
        int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p);
116
        if (s.extra || sym < 0)
117
          break;
118
        outBuffer[i] = (Byte)sym;
119
      }
120
      if (i != outSize)
121
        res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
122
      else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc))
123
        res = SZ_ERROR_DATA;
124
    }
125
  }
126
  Ppmd7_Free(&ppmd, allocMain);
127
  return res;
128
}
129
 
130
#endif
131
 
132
 
133
static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
134
    Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
135
{
136
  CLzmaDec state;
137
  SRes res = SZ_OK;
138
 
139
  LzmaDec_Construct(&state);
140
  RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain));
141
  state.dic = outBuffer;
142
  state.dicBufSize = outSize;
143
  LzmaDec_Init(&state);
144
 
145
  for (;;)
146
  {
147
    const void *inBuf = NULL;
148
    size_t lookahead = (1 << 18);
149
    if (lookahead > inSize)
150
      lookahead = (size_t)inSize;
151
    res = inStream->Look(inStream, &inBuf, &lookahead);
152
    if (res != SZ_OK)
153
      break;
154
 
155
    {
156
      SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
157
      ELzmaStatus status;
158
      res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
159
      lookahead -= inProcessed;
160
      inSize -= inProcessed;
161
      if (res != SZ_OK)
162
        break;
163
      if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos))
164
      {
165
        if (state.dicBufSize != outSize || lookahead != 0 ||
166
            (status != LZMA_STATUS_FINISHED_WITH_MARK &&
167
             status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
168
          res = SZ_ERROR_DATA;
169
        break;
170
      }
171
      res = inStream->Skip((void *)inStream, inProcessed);
172
      if (res != SZ_OK)
173
        break;
174
    }
175
  }
176
 
177
  LzmaDec_FreeProbs(&state, allocMain);
178
  return res;
179
}
180
 
181
 
182
#ifndef _7Z_NO_METHOD_LZMA2
183
 
184
static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
185
    Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
186
{
187
  CLzma2Dec state;
188
  SRes res = SZ_OK;
189
 
190
  Lzma2Dec_Construct(&state);
191
  if (propsSize != 1)
192
    return SZ_ERROR_DATA;
193
  RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain));
194
  state.decoder.dic = outBuffer;
195
  state.decoder.dicBufSize = outSize;
196
  Lzma2Dec_Init(&state);
197
 
198
  for (;;)
199
  {
200
    const void *inBuf = NULL;
201
    size_t lookahead = (1 << 18);
202
    if (lookahead > inSize)
203
      lookahead = (size_t)inSize;
204
    res = inStream->Look(inStream, &inBuf, &lookahead);
205
    if (res != SZ_OK)
206
      break;
207
 
208
    {
209
      SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
210
      ELzmaStatus status;
211
      res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
212
      lookahead -= inProcessed;
213
      inSize -= inProcessed;
214
      if (res != SZ_OK)
215
        break;
216
      if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos))
217
      {
218
        if (state.decoder.dicBufSize != outSize || lookahead != 0 ||
219
            (status != LZMA_STATUS_FINISHED_WITH_MARK))
220
          res = SZ_ERROR_DATA;
221
        break;
222
      }
223
      res = inStream->Skip((void *)inStream, inProcessed);
224
      if (res != SZ_OK)
225
        break;
226
    }
227
  }
228
 
229
  Lzma2Dec_FreeProbs(&state, allocMain);
230
  return res;
231
}
232
 
233
#endif
234
 
235
 
236
static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
237
{
238
  while (inSize > 0)
239
  {
240
    const void *inBuf;
241
    size_t curSize = (1 << 18);
242
    if (curSize > inSize)
243
      curSize = (size_t)inSize;
244
    RINOK(inStream->Look(inStream, &inBuf, &curSize));
245
    if (curSize == 0)
246
      return SZ_ERROR_INPUT_EOF;
247
    memcpy(outBuffer, inBuf, curSize);
248
    outBuffer += curSize;
249
    inSize -= curSize;
250
    RINOK(inStream->Skip((void *)inStream, curSize));
251
  }
252
  return SZ_OK;
253
}
254
 
255
static Bool IS_MAIN_METHOD(UInt32 m)
256
{
257
  switch (m)
258
  {
259
    case k_Copy:
260
    case k_LZMA:
261
    #ifndef _7Z_NO_METHOD_LZMA2
262
    case k_LZMA2:
263
    #endif
264
    #ifdef _7ZIP_PPMD_SUPPPORT
265
    case k_PPMD:
266
    #endif
267
      return True;
268
  }
269
  return False;
270
}
271
 
272
static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)
273
{
274
  return
275
      c->NumStreams == 1
276
      /* && c->MethodID <= (UInt32)0xFFFFFFFF */
277
      && IS_MAIN_METHOD((UInt32)c->MethodID);
278
}
279
 
280
#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4)
281
 
282
static SRes CheckSupportedFolder(const CSzFolder *f)
283
{
284
  if (f->NumCoders < 1 || f->NumCoders > 4)
285
    return SZ_ERROR_UNSUPPORTED;
286
  if (!IS_SUPPORTED_CODER(&f->Coders[0]))
287
    return SZ_ERROR_UNSUPPORTED;
288
  if (f->NumCoders == 1)
289
  {
290
    if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0)
291
      return SZ_ERROR_UNSUPPORTED;
292
    return SZ_OK;
293
  }
294
 
295
 
296
  #ifndef _7Z_NO_METHODS_FILTERS
297
 
298
  if (f->NumCoders == 2)
299
  {
300
    const CSzCoderInfo *c = &f->Coders[1];
301
    if (
302
        /* c->MethodID > (UInt32)0xFFFFFFFF || */
303
        c->NumStreams != 1
304
        || f->NumPackStreams != 1
305
        || f->PackStreams[0] != 0
306
        || f->NumBonds != 1
307
        || f->Bonds[0].InIndex != 1
308
        || f->Bonds[0].OutIndex != 0)
309
      return SZ_ERROR_UNSUPPORTED;
310
    switch ((UInt32)c->MethodID)
311
    {
312
      case k_Delta:
313
      case k_BCJ:
314
      case k_PPC:
315
      case k_IA64:
316
      case k_SPARC:
317
      case k_ARM:
318
      case k_ARMT:
319
        break;
320
      default:
321
        return SZ_ERROR_UNSUPPORTED;
322
    }
323
    return SZ_OK;
324
  }
325
 
326
  #endif
327
 
328
 
329
  if (f->NumCoders == 4)
330
  {
331
    if (!IS_SUPPORTED_CODER(&f->Coders[1])
332
        || !IS_SUPPORTED_CODER(&f->Coders[2])
333
        || !IS_BCJ2(&f->Coders[3]))
334
      return SZ_ERROR_UNSUPPORTED;
335
    if (f->NumPackStreams != 4
336
        || f->PackStreams[0] != 2
337
        || f->PackStreams[1] != 6
338
        || f->PackStreams[2] != 1
339
        || f->PackStreams[3] != 0
340
        || f->NumBonds != 3
341
        || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0
342
        || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1
343
        || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2)
344
      return SZ_ERROR_UNSUPPORTED;
345
    return SZ_OK;
346
  }
347
 
348
  return SZ_ERROR_UNSUPPORTED;
349
}
350
 
351
#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
352
 
353
static SRes SzFolder_Decode2(const CSzFolder *folder,
354
    const Byte *propsData,
355
    const UInt64 *unpackSizes,
356
    const UInt64 *packPositions,
357
    ILookInStream *inStream, UInt64 startPos,
358
    Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain,
359
    Byte *tempBuf[])
360
{
361
  UInt32 ci;
362
  SizeT tempSizes[3] = { 0, 0, 0};
363
  SizeT tempSize3 = 0;
364
  Byte *tempBuf3 = 0;
365
 
366
  RINOK(CheckSupportedFolder(folder));
367
 
368
  for (ci = 0; ci < folder->NumCoders; ci++)
369
  {
370
    const CSzCoderInfo *coder = &folder->Coders[ci];
371
 
372
    if (IS_MAIN_METHOD((UInt32)coder->MethodID))
373
    {
374
      UInt32 si = 0;
375
      UInt64 offset;
376
      UInt64 inSize;
377
      Byte *outBufCur = outBuffer;
378
      SizeT outSizeCur = outSize;
379
      if (folder->NumCoders == 4)
380
      {
381
        UInt32 indices[] = { 3, 2, 0 };
382
        UInt64 unpackSize = unpackSizes[ci];
383
        si = indices[ci];
384
        if (ci < 2)
385
        {
386
          Byte *temp;
387
          outSizeCur = (SizeT)unpackSize;
388
          if (outSizeCur != unpackSize)
389
            return SZ_ERROR_MEM;
390
          temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
391
          if (!temp && outSizeCur != 0)
392
            return SZ_ERROR_MEM;
393
          outBufCur = tempBuf[1 - ci] = temp;
394
          tempSizes[1 - ci] = outSizeCur;
395
        }
396
        else if (ci == 2)
397
        {
398
          if (unpackSize > outSize) /* check it */
399
            return SZ_ERROR_PARAM;
400
          tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
401
          tempSize3 = outSizeCur = (SizeT)unpackSize;
402
        }
403
        else
404
          return SZ_ERROR_UNSUPPORTED;
405
      }
406
      offset = packPositions[si];
407
      inSize = packPositions[si + 1] - offset;
408
      RINOK(LookInStream_SeekTo(inStream, startPos + offset));
409
 
410
      if (coder->MethodID == k_Copy)
411
      {
412
        if (inSize != outSizeCur) /* check it */
413
          return SZ_ERROR_DATA;
414
        RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
415
      }
416
      else if (coder->MethodID == k_LZMA)
417
      {
418
        RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
419
      }
420
      #ifndef _7Z_NO_METHOD_LZMA2
421
      else if (coder->MethodID == k_LZMA2)
422
      {
423
        RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
424
      }
425
      #endif
426
      #ifdef _7ZIP_PPMD_SUPPPORT
427
      else if (coder->MethodID == k_PPMD)
428
      {
429
        RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
430
      }
431
      #endif
432
      else
433
        return SZ_ERROR_UNSUPPORTED;
434
    }
435
    else if (coder->MethodID == k_BCJ2)
436
    {
437
      UInt64 offset = packPositions[1];
438
      UInt64 s3Size = packPositions[2] - offset;
439
 
440
      if (ci != 3)
441
        return SZ_ERROR_UNSUPPORTED;
442
 
443
      tempSizes[2] = (SizeT)s3Size;
444
      if (tempSizes[2] != s3Size)
445
        return SZ_ERROR_MEM;
446
      tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]);
447
      if (!tempBuf[2] && tempSizes[2] != 0)
448
        return SZ_ERROR_MEM;
449
 
450
      RINOK(LookInStream_SeekTo(inStream, startPos + offset));
451
      RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2]));
452
 
453
      if ((tempSizes[0] & 3) != 0 ||
454
          (tempSizes[1] & 3) != 0 ||
455
          tempSize3 + tempSizes[0] + tempSizes[1] != outSize)
456
        return SZ_ERROR_DATA;
457
 
458
      {
459
        CBcj2Dec p;
460
 
461
        p.bufs[0] = tempBuf3;   p.lims[0] = tempBuf3 + tempSize3;
462
        p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0];
463
        p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1];
464
        p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2];
465
 
466
        p.dest = outBuffer;
467
        p.destLim = outBuffer + outSize;
468
 
469
        Bcj2Dec_Init(&p);
470
        RINOK(Bcj2Dec_Decode(&p));
471
 
472
        {
473
          unsigned i;
474
          for (i = 0; i < 4; i++)
475
            if (p.bufs[i] != p.lims[i])
476
              return SZ_ERROR_DATA;
477
 
478
          if (!Bcj2Dec_IsFinished(&p))
479
            return SZ_ERROR_DATA;
480
 
481
          if (p.dest != p.destLim
482
             || p.state != BCJ2_STREAM_MAIN)
483
            return SZ_ERROR_DATA;
484
        }
485
      }
486
    }
487
    #ifndef _7Z_NO_METHODS_FILTERS
488
    else if (ci == 1)
489
    {
490
      if (coder->MethodID == k_Delta)
491
      {
492
        if (coder->PropsSize != 1)
493
          return SZ_ERROR_UNSUPPORTED;
494
        {
495
          Byte state[DELTA_STATE_SIZE];
496
          Delta_Init(state);
497
          Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize);
498
        }
499
      }
500
      else
501
      {
502
        if (coder->PropsSize != 0)
503
          return SZ_ERROR_UNSUPPORTED;
504
        switch (coder->MethodID)
505
        {
506
          case k_BCJ:
507
          {
508
            UInt32 state;
509
            x86_Convert_Init(state);
510
            x86_Convert(outBuffer, outSize, 0, &state, 0);
511
            break;
512
          }
513
          CASE_BRA_CONV(PPC)
514
          CASE_BRA_CONV(IA64)
515
          CASE_BRA_CONV(SPARC)
516
          CASE_BRA_CONV(ARM)
517
          CASE_BRA_CONV(ARMT)
518
          default:
519
            return SZ_ERROR_UNSUPPORTED;
520
        }
521
      }
522
    }
523
    #endif
524
    else
525
      return SZ_ERROR_UNSUPPORTED;
526
  }
527
 
528
  return SZ_OK;
529
}
530
 
531
 
532
SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
533
    ILookInStream *inStream, UInt64 startPos,
534
    Byte *outBuffer, size_t outSize,
535
    ISzAlloc *allocMain)
536
{
537
  SRes res;
538
  CSzFolder folder;
539
  CSzData sd;
540
  CSzData sdSizes;
541
 
542
  const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex];
543
  sd.Data = data;
544
  sd.Size = p->FoCodersOffsets[folderIndex + 1] - p->FoCodersOffsets[folderIndex];
545
 
546
  sdSizes.Data = p->UnpackSizesData + p->FoSizesOffsets[folderIndex];
547
  sdSizes.Size =
548
      p->FoSizesOffsets[folderIndex + 1] -
549
      p->FoSizesOffsets[folderIndex];
550
 
551
  res = SzGetNextFolderItem(&folder, &sd, &sdSizes);
552
 
553
  if (res != SZ_OK)
554
    return res;
555
 
556
  if (sd.Size != 0 || outSize != folder.CodersUnpackSizes[folder.UnpackStream])
557
    return SZ_ERROR_FAIL;
558
  {
559
    unsigned i;
560
    Byte *tempBuf[3] = { 0, 0, 0};
561
    res = SzFolder_Decode2(&folder, data, folder.CodersUnpackSizes,
562
        p->PackPositions + p->FoStartPackStreamIndex[folderIndex],
563
        inStream, startPos,
564
        outBuffer, (SizeT)outSize, allocMain, tempBuf);
565
    for (i = 0; i < 3; i++)
566
      IAlloc_Free(allocMain, tempBuf[i]);
567
    return res;
568
  }
569
}