Coverage Report

Created: 2025-04-11 06:56

/src/unrar/unpack50mt.cpp
Line
Count
Source (jump to first uncovered line)
1
// 2023.09.09: 0x400000 and 2 are optimal for i9-12900K.
2
// Further increasing the buffer size reduced the extraction speed.
3
9.20k
#define UNP_READ_SIZE_MT        0x400000
4
46.4k
#define UNP_BLOCKS_PER_THREAD          2
5
6
7
struct UnpackThreadDataList
8
{
9
  UnpackThreadData *D;
10
  uint BlockCount;
11
};
12
13
14
THREAD_PROC(UnpackDecodeThread)
15
5
{
16
5
  UnpackThreadDataList *DL=(UnpackThreadDataList *)Data;
17
10
  for (uint I=0;I<DL->BlockCount;I++)
18
5
    DL->D->UnpackPtr->UnpackDecode(DL->D[I]);
19
5
}
20
21
22
void Unpack::InitMT()
23
2.42k
{
24
2.42k
  if (ReadBufMT==NULL)
25
2.24k
  {
26
    // Even getbits32 can read up to 3 additional bytes after current
27
    // and our block header and table reading code can look much further.
28
    // Let's allocate the additional space here, so we do not need to check
29
    // bounds for every bit field access.
30
2.24k
    const size_t Overflow=1024;
31
32
2.24k
    ReadBufMT=new byte[UNP_READ_SIZE_MT+Overflow];
33
2.24k
    memset(ReadBufMT,0,UNP_READ_SIZE_MT+Overflow);
34
2.24k
  }
35
2.42k
  if (UnpThreadData==NULL)
36
2.24k
  {
37
2.24k
    uint MaxItems=MaxUserThreads*UNP_BLOCKS_PER_THREAD;
38
2.24k
    UnpThreadData=new UnpackThreadData[MaxItems];
39
2.24k
    memset(UnpThreadData,0,sizeof(UnpackThreadData)*MaxItems);
40
41
38.0k
    for (uint I=0;I<MaxItems;I++)
42
35.8k
    {
43
35.8k
      UnpackThreadData *CurData=UnpThreadData+I;
44
35.8k
      if (CurData->Decoded==NULL)
45
35.8k
      {
46
        // Typical number of items in RAR blocks does not exceed 0x4000.
47
35.8k
        CurData->DecodedAllocated=0x4100;
48
        // It will be freed in the object destructor, not in this file.
49
35.8k
        CurData->Decoded=(UnpackDecodedItem *)malloc(CurData->DecodedAllocated*sizeof(UnpackDecodedItem));
50
35.8k
        if (CurData->Decoded==NULL)
51
0
          ErrHandler.MemoryError();
52
35.8k
      }
53
35.8k
    }
54
2.24k
  }
55
2.42k
}
56
57
58
void Unpack::Unpack5MT(bool Solid)
59
2.42k
{
60
2.42k
  InitMT();
61
2.42k
  UnpInitData(Solid);
62
63
41.2k
  for (uint I=0;I<MaxUserThreads*UNP_BLOCKS_PER_THREAD;I++)
64
38.8k
  {
65
38.8k
    UnpackThreadData *CurData=UnpThreadData+I;
66
38.8k
    CurData->LargeBlock=false;
67
38.8k
    CurData->Incomplete=false;
68
38.8k
  }
69
70
2.42k
  UnpThreadData[0].BlockHeader=BlockHeader;
71
2.42k
  UnpThreadData[0].BlockTables=BlockTables;
72
2.42k
  uint LastBlockNum=0;
73
74
2.42k
  int DataSize=0;
75
2.42k
  int BlockStart=0;
76
77
78
  // 'true' if we found a block too large for multithreaded extraction,
79
  // so we switched to single threaded mode until the end of file.
80
  // Large blocks could cause too high memory use in multithreaded mode.
81
2.42k
  bool LargeBlock=false;
82
83
2.42k
  bool Done=false;
84
7.13k
  while (!Done)
85
4.72k
  {
86
    // Data amount, which is guaranteed to fit block header and tables,
87
    // so we can safely read them without additional checks.
88
4.72k
    const int TooSmallToProcess=1024;
89
90
4.72k
    int ReadSize=UnpIO->UnpRead(ReadBufMT+DataSize,(UNP_READ_SIZE_MT-DataSize)&~0xf);
91
4.72k
    if (ReadSize<0)
92
2
      break;
93
4.72k
    DataSize+=ReadSize;
94
4.72k
    if (DataSize==0)
95
12
      break;
96
97
    // First read chunk can be small if we are near the end of volume
98
    // and we want it to fit block header and tables.
99
4.71k
    if (ReadSize>0 && DataSize<TooSmallToProcess)
100
1.72k
      continue;
101
102
2.98k
    while (BlockStart<DataSize && !Done)
103
2.98k
    {
104
2.98k
      uint BlockNumber=0,BlockNumberMT=0;
105
2.99k
      while (BlockNumber<MaxUserThreads*UNP_BLOCKS_PER_THREAD)
106
2.99k
      {
107
2.99k
        UnpackThreadData *CurData=UnpThreadData+BlockNumber;
108
2.99k
        LastBlockNum=BlockNumber;
109
2.99k
        CurData->UnpackPtr=this;
110
111
        // 'Incomplete' thread is present. This is a thread processing block
112
        // in the end of buffer, split between two read operations.
113
2.99k
        if (CurData->Incomplete)
114
555
          CurData->DataSize=DataSize;
115
2.43k
        else
116
2.43k
        {
117
2.43k
          CurData->Inp.SetExternalBuffer(ReadBufMT+BlockStart);
118
2.43k
          CurData->Inp.InitBitInput();
119
2.43k
          CurData->DataSize=DataSize-BlockStart;
120
2.43k
          if (CurData->DataSize==0)
121
0
            break;
122
2.43k
          CurData->DamagedData=false;
123
2.43k
          CurData->HeaderRead=false;
124
2.43k
          CurData->TableRead=false;
125
2.43k
        }
126
127
        // We should not use 'last block in file' block flag here unless
128
        // we'll check the block size, because even if block is last in file,
129
        // it can exceed the current buffer and require more reading.
130
2.99k
        CurData->NoDataLeft=(ReadSize==0);
131
132
2.99k
        CurData->Incomplete=false;
133
2.99k
        CurData->ThreadNumber=BlockNumber;
134
135
2.99k
        if (!CurData->HeaderRead)
136
2.43k
        {
137
2.43k
          CurData->HeaderRead=true;
138
2.43k
          if (!ReadBlockHeader(CurData->Inp,CurData->BlockHeader) ||
139
2.43k
              !CurData->BlockHeader.TablePresent && !TablesRead5)
140
292
          {
141
292
            Done=true;
142
292
            break;
143
292
          }
144
2.14k
          TablesRead5=true;
145
2.14k
        }
146
147
        // To prevent too high memory use we switch to single threaded mode
148
        // if block exceeds this size. Typically RAR blocks do not exceed
149
        // 64 KB, so this protection should not affect most of valid archives.
150
2.70k
        const int LargeBlockSize=0x20000;
151
2.70k
        if (LargeBlock || CurData->BlockHeader.BlockSize>LargeBlockSize)
152
1.50k
          LargeBlock=CurData->LargeBlock=true;
153
1.19k
        else
154
1.19k
          BlockNumberMT++; // Number of normal blocks processed in MT mode.
155
156
2.70k
        BlockStart+=CurData->BlockHeader.HeaderSize+CurData->BlockHeader.BlockSize;
157
158
2.70k
        BlockNumber++;
159
160
2.70k
        int DataLeft=DataSize-BlockStart;
161
2.70k
        if (DataLeft>=0 && CurData->BlockHeader.LastBlockInFile)
162
136
          break;
163
164
        // For second and following threads we move smaller blocks to buffer
165
        // start to ensure that we have enough data to fit block header
166
        // and tables.
167
2.56k
        if (DataLeft<TooSmallToProcess)
168
2.56k
          break;
169
2.56k
      }
170
171
//#undef USE_THREADS
172
2.98k
      UnpackThreadDataList UTDArray[MaxPoolThreads];
173
2.98k
      uint UTDArrayPos=0;
174
175
2.98k
      uint MaxBlockPerThread=BlockNumberMT/MaxUserThreads;
176
2.98k
      if (BlockNumberMT%MaxUserThreads!=0)
177
1.19k
        MaxBlockPerThread++;
178
179
      // Decode all normal blocks until the first 'large' if any.
180
4.18k
      for (uint CurBlock=0;CurBlock<BlockNumberMT;CurBlock+=MaxBlockPerThread)
181
1.19k
      {
182
1.19k
        UnpackThreadDataList *UTD=UTDArray+UTDArrayPos++;
183
1.19k
        UTD->D=UnpThreadData+CurBlock;
184
1.19k
        UTD->BlockCount=Min(MaxBlockPerThread,BlockNumberMT-CurBlock);
185
186
1.19k
#ifdef USE_THREADS
187
1.19k
        if (BlockNumber==1)
188
1.18k
          UnpackDecode(*UTD->D);
189
5
        else
190
5
          UnpThreadPool->AddTask(UnpackDecodeThread,(void*)UTD);
191
#else
192
        for (uint I=0;I<UTD->BlockCount;I++)
193
          UnpackDecode(UTD->D[I]);
194
#endif
195
1.19k
      }
196
197
2.98k
      if (BlockNumber==0)
198
290
        break;
199
200
2.69k
#ifdef USE_THREADS
201
2.69k
      UnpThreadPool->WaitDone();
202
2.69k
#endif
203
204
2.69k
      bool IncompleteThread=false;
205
206
2.72k
      for (uint Block=0;Block<BlockNumber;Block++)
207
2.70k
      {
208
2.70k
        UnpackThreadData *CurData=UnpThreadData+Block;
209
2.70k
        if (!CurData->LargeBlock && !ProcessDecoded(*CurData) ||
210
2.70k
            CurData->LargeBlock && !UnpackLargeBlock(*CurData) ||
211
2.70k
            CurData->DamagedData)
212
82
        {
213
82
          Done=true;
214
82
          break;
215
82
        }
216
2.61k
        if (CurData->Incomplete)
217
2.46k
        {
218
2.46k
          int BufPos=int(CurData->Inp.InBuf+CurData->Inp.InAddr-ReadBufMT);
219
2.46k
          if (DataSize<=BufPos) // Thread exceeded input buffer boundary.
220
1.91k
          {
221
1.91k
            Done=true;
222
1.91k
            break;
223
1.91k
          }
224
555
          IncompleteThread=true;
225
555
          memmove(ReadBufMT,ReadBufMT+BufPos,DataSize-BufPos);
226
555
          CurData->BlockHeader.BlockSize-=CurData->Inp.InAddr-CurData->BlockHeader.BlockStart;
227
555
          CurData->BlockHeader.HeaderSize=0;
228
555
          CurData->BlockHeader.BlockStart=0;
229
555
          CurData->Inp.InBuf=ReadBufMT;
230
555
          CurData->Inp.InAddr=0;
231
232
555
          if (Block!=0)
233
1
          {
234
            // Move the incomplete thread entry to the first position,
235
            // so we'll start processing from it. Preserve the original
236
            // buffer for decoded data.
237
1
            UnpackDecodedItem *Decoded=UnpThreadData[0].Decoded;
238
1
            uint DecodedAllocated=UnpThreadData[0].DecodedAllocated;
239
1
            UnpThreadData[0]=*CurData;
240
1
            UnpThreadData[0].Decoded=Decoded;
241
1
            UnpThreadData[0].DecodedAllocated=DecodedAllocated;
242
1
            CurData->Incomplete=false;
243
1
          }
244
245
555
          BlockStart=0;
246
555
          DataSize-=BufPos;
247
555
          break;
248
2.46k
        }
249
154
        else
250
154
          if (CurData->BlockHeader.LastBlockInFile)
251
126
          {
252
126
            Done=true;
253
126
            break;
254
126
          }
255
2.61k
      }
256
257
2.69k
      if (IncompleteThread || Done)
258
2.67k
        break; // Current buffer is done, read more data or quit.
259
23
      else
260
23
      {
261
23
        int DataLeft=DataSize-BlockStart;
262
23
        if (DataLeft<TooSmallToProcess)
263
23
        {
264
23
          if (DataLeft<0) // Invalid data, must not happen in valid archive.
265
2
          {
266
2
            Done=true;
267
2
            break;
268
2
          }
269
270
          // If we do not have incomplete thread and have some data
271
          // in the end of buffer, too small for single thread,
272
          // let's move it to beginning of next buffer.
273
21
          if (DataLeft>0)
274
19
            memmove(ReadBufMT,ReadBufMT+BlockStart,DataLeft);
275
21
          DataSize=DataLeft;
276
21
          BlockStart=0;
277
21
          break; // Current buffer is done, try to read more data.
278
23
        }
279
23
      }
280
2.69k
    }
281
2.98k
  }
282
2.42k
  UnpPtr=WrapUp(UnpPtr); // ProcessDecoded and maybe others can leave UnpPtr >= MaxWinSize here.
283
2.42k
  UnpWriteBuf();
284
285
2.42k
  BlockHeader=UnpThreadData[LastBlockNum].BlockHeader;
286
2.42k
  BlockTables=UnpThreadData[LastBlockNum].BlockTables;
287
2.42k
}
288
289
290
// Decode Huffman block and save decoded data to memory.
291
void Unpack::UnpackDecode(UnpackThreadData &D)
292
1.19k
{
293
1.19k
  if (!D.TableRead)
294
1.04k
  {
295
1.04k
    D.TableRead=true;
296
1.04k
    if (!ReadTables(D.Inp,D.BlockHeader,D.BlockTables))
297
4
    {
298
4
      D.DamagedData=true;
299
4
      return;
300
4
    }
301
1.04k
  }
302
303
1.18k
  if (D.Inp.InAddr>D.BlockHeader.HeaderSize+D.BlockHeader.BlockSize)
304
14
  {
305
14
    D.DamagedData=true;
306
14
    return;
307
14
  }
308
309
1.17k
  D.DecodedSize=0;
310
1.17k
  int BlockBorder=D.BlockHeader.BlockStart+D.BlockHeader.BlockSize-1;
311
312
  // Reserve enough space even for filter entry.
313
1.17k
  int DataBorder=D.DataSize-16;
314
1.17k
  int ReadBorder=Min(BlockBorder,DataBorder);
315
316
3.44M
  while (true)
317
3.44M
  {
318
3.44M
    if (D.Inp.InAddr>=ReadBorder)
319
15.8k
    {
320
15.8k
      if (D.Inp.InAddr>BlockBorder || D.Inp.InAddr==BlockBorder && 
321
15.7k
          D.Inp.InBit>=D.BlockHeader.BlockBitSize)
322
164
        break;
323
324
      // If we do not have any more data in file to read, we must process
325
      // what we have until last byte. Otherwise we can return and append
326
      // more data to unprocessed few bytes.
327
15.6k
      if ((D.Inp.InAddr>=DataBorder) && !D.NoDataLeft || D.Inp.InAddr>=D.DataSize)
328
1.01k
      {
329
1.01k
        D.Incomplete=true;
330
1.01k
        break;
331
1.01k
      }
332
15.6k
    }
333
3.43M
    if (D.DecodedSize>D.DecodedAllocated-8) // Filter can use several slots.
334
18
    {
335
18
      D.DecodedAllocated=D.DecodedAllocated*2;
336
18
      void *Decoded=realloc(D.Decoded,D.DecodedAllocated*sizeof(UnpackDecodedItem));
337
18
      if (Decoded==NULL)
338
0
        ErrHandler.MemoryError(); // D.Decoded will be freed in the destructor.
339
18
      D.Decoded=(UnpackDecodedItem *)Decoded;
340
18
    }
341
342
3.43M
    UnpackDecodedItem *CurItem=D.Decoded+D.DecodedSize++;
343
344
3.43M
    uint MainSlot=DecodeNumber(D.Inp,&D.BlockTables.LD);
345
3.43M
    if (MainSlot<256)
346
3.04M
    {
347
3.04M
      if (D.DecodedSize>1)
348
3.04M
      {
349
3.04M
        UnpackDecodedItem *PrevItem=CurItem-1;
350
3.04M
        if (PrevItem->Type==UNPDT_LITERAL && PrevItem->Length<ASIZE(PrevItem->Literal)-1)
351
2.64M
        {
352
2.64M
          PrevItem->Length++;
353
2.64M
          PrevItem->Literal[PrevItem->Length]=(byte)MainSlot;
354
2.64M
          D.DecodedSize--;
355
2.64M
          continue;
356
2.64M
        }
357
3.04M
      }
358
406k
      CurItem->Type=UNPDT_LITERAL;
359
406k
      CurItem->Literal[0]=(byte)MainSlot;
360
406k
      CurItem->Length=0;
361
406k
      continue;
362
3.04M
    }
363
391k
    if (MainSlot>=262)
364
89.9k
    {
365
89.9k
      uint Length=SlotToLength(D.Inp,MainSlot-262);
366
367
89.9k
      size_t Distance=1;
368
89.9k
      uint DBits,DistSlot=DecodeNumber(D.Inp,&D.BlockTables.DD);
369
89.9k
      if (DistSlot<4)
370
67.3k
      {
371
67.3k
        DBits=0;
372
67.3k
        Distance+=DistSlot;
373
67.3k
      }
374
22.5k
      else
375
22.5k
      {
376
22.5k
        DBits=DistSlot/2 - 1;
377
22.5k
        Distance+=size_t(2 | (DistSlot & 1)) << DBits;
378
22.5k
      }
379
380
89.9k
      if (DBits>0)
381
22.5k
      {
382
22.5k
        if (DBits>=4)
383
11.6k
        {
384
11.6k
          if (DBits>4)
385
8.76k
          {
386
            // It is also possible to always use getbits64() here.
387
8.76k
            if (DBits>36)
388
326
              Distance+=( ( size_t(D.Inp.getbits64() ) >> (68-DBits) ) << 4 );
389
8.43k
            else
390
8.43k
              Distance+=( ( size_t(D.Inp.getbits32() ) >> (36-DBits) ) << 4 );
391
8.76k
            D.Inp.addbits(DBits-4);
392
8.76k
          }
393
11.6k
          uint LowDist=DecodeNumber(D.Inp,&D.BlockTables.LDD);
394
11.6k
          Distance+=LowDist;
395
396
          // Distance can be 0 for multiples of 4 GB as result of size_t
397
          // overflow in 32-bit build. Its lower 32-bit can also erroneously
398
          // fit into dictionary after truncating upper 32-bits. Replace such
399
          // invalid distances with -1, so CopyString sets 0 data for them.
400
          // DBits>=30 also as DistSlot>=62 indicate distances >=0x80000001.
401
11.6k
          if (sizeof(Distance)==4 && DBits>=30)
402
0
            Distance=(size_t)-1;
403
11.6k
        }
404
10.8k
        else
405
10.8k
        {
406
10.8k
          Distance+=D.Inp.getbits()>>(16-DBits);
407
10.8k
          D.Inp.addbits(DBits);
408
10.8k
        }
409
22.5k
      }
410
411
89.9k
      if (Distance>0x100)
412
5.43k
      {
413
5.43k
        Length++;
414
5.43k
        if (Distance>0x2000)
415
3.62k
        {
416
3.62k
          Length++;
417
3.62k
          if (Distance>0x40000)
418
2.62k
            Length++;
419
3.62k
        }
420
5.43k
      }
421
422
89.9k
      CurItem->Type=UNPDT_MATCH;
423
89.9k
      CurItem->Length=(ushort)Length;
424
89.9k
      CurItem->Distance=Distance;
425
89.9k
      continue;
426
89.9k
    }
427
302k
    if (MainSlot==256)
428
13.4k
    {
429
13.4k
      UnpackFilter Filter;
430
13.4k
      ReadFilter(D.Inp,Filter);
431
432
13.4k
      CurItem->Type=UNPDT_FILTER;
433
13.4k
      CurItem->Length=Filter.Type;
434
13.4k
      CurItem->Distance=Filter.BlockStart;
435
436
13.4k
      CurItem=D.Decoded+D.DecodedSize++;
437
438
13.4k
      CurItem->Type=UNPDT_FILTER;
439
13.4k
      CurItem->Length=Filter.Channels;
440
13.4k
      CurItem->Distance=Filter.BlockLength;
441
442
13.4k
      continue;
443
13.4k
    }
444
288k
    if (MainSlot==257)
445
283k
    {
446
283k
      CurItem->Type=UNPDT_FULLREP;
447
283k
      continue;
448
283k
    }
449
4.57k
    if (MainSlot<262)
450
4.57k
    {
451
4.57k
      CurItem->Type=UNPDT_REP;
452
4.57k
      CurItem->Distance=MainSlot-258;
453
4.57k
      uint LengthSlot=DecodeNumber(D.Inp,&D.BlockTables.RD);
454
4.57k
      uint Length=SlotToLength(D.Inp,LengthSlot);
455
4.57k
      CurItem->Length=(ushort)Length;
456
4.57k
      continue;
457
4.57k
    }
458
4.57k
  }
459
1.17k
}
460
461
462
// Process decoded Huffman block data.
463
bool Unpack::ProcessDecoded(UnpackThreadData &D)
464
1.19k
{
465
1.19k
  UnpackDecodedItem *Item=D.Decoded,*Border=D.Decoded+D.DecodedSize;
466
796k
  while (Item<Border)
467
795k
  {
468
795k
    UnpPtr=WrapUp(UnpPtr);
469
470
795k
    FirstWinDone|=(PrevPtr>UnpPtr);
471
795k
    PrevPtr=UnpPtr;
472
473
795k
    if (WrapDown(WriteBorder-UnpPtr)<=MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
474
2.40k
    {
475
2.40k
      UnpWriteBuf();
476
2.40k
      if (WrittenFileSize>DestUnpSize)
477
25
        return false;
478
2.40k
    }
479
480
795k
    if (Item->Type==UNPDT_LITERAL)
481
405k
    {
482
405k
#if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED)
483
405k
      if (Item->Length==7 && UnpPtr<MaxWinSize-8)
484
375k
      {
485
375k
        *(uint64 *)(Window+UnpPtr)=*(uint64 *)(Item->Literal);
486
375k
         UnpPtr+=8;
487
375k
      }
488
30.8k
      else
489
30.8k
#endif
490
78.4k
        for (uint I=0;I<=Item->Length;I++)
491
47.5k
          Window[WrapUp(UnpPtr++)]=Item->Literal[I];
492
405k
    }
493
389k
    else
494
389k
      if (Item->Type==UNPDT_MATCH)
495
88.1k
      {
496
88.1k
        InsertOldDist(Item->Distance);
497
88.1k
        LastLength=Item->Length;
498
88.1k
        CopyString(Item->Length,Item->Distance);
499
88.1k
      }
500
301k
      else
501
301k
        if (Item->Type==UNPDT_REP)
502
4.57k
        {
503
4.57k
          size_t Distance=OldDist[Item->Distance];
504
12.7k
          for (size_t I=Item->Distance;I>0;I--)
505
8.16k
            OldDist[I]=OldDist[I-1];
506
4.57k
          OldDist[0]=Distance;
507
4.57k
          LastLength=Item->Length;
508
4.57k
          CopyString(Item->Length,Distance);
509
4.57k
        }
510
297k
        else
511
297k
          if (Item->Type==UNPDT_FULLREP)
512
283k
          {
513
283k
            if (LastLength!=0)
514
271k
              CopyString(LastLength,OldDist[0]);
515
283k
          }
516
13.3k
          else
517
13.3k
            if (Item->Type==UNPDT_FILTER)
518
13.3k
            {
519
13.3k
              UnpackFilter Filter;
520
521
13.3k
              Filter.Type=(byte)Item->Length;
522
13.3k
              Filter.BlockStart=Item->Distance;
523
524
13.3k
              Item++;
525
526
13.3k
              Filter.Channels=(byte)Item->Length;
527
13.3k
              Filter.BlockLength=(uint)Item->Distance;
528
529
13.3k
              AddFilter(Filter);
530
13.3k
            }
531
795k
    Item++;
532
795k
  }
533
1.16k
  return true;
534
1.19k
}
535
536
537
// For large blocks we decode and process in same function in single threaded
538
// mode, so we do not need to store intermediate data in memory.
539
bool Unpack::UnpackLargeBlock(UnpackThreadData &D)
540
1.50k
{
541
1.50k
  if (!D.TableRead)
542
1.10k
  {
543
1.10k
    D.TableRead=true;
544
1.10k
    if (!ReadTables(D.Inp,D.BlockHeader,D.BlockTables))
545
1
    {
546
1
      D.DamagedData=true;
547
1
      return false;
548
1
    }
549
1.10k
  }
550
551
1.50k
  if (D.Inp.InAddr>D.BlockHeader.HeaderSize+D.BlockHeader.BlockSize)
552
0
  {
553
0
    D.DamagedData=true;
554
0
    return false;
555
0
  }
556
557
1.50k
  int BlockBorder=D.BlockHeader.BlockStart+D.BlockHeader.BlockSize-1;
558
559
  // Reserve enough space even for filter entry.
560
1.50k
  int DataBorder=D.DataSize-16;
561
1.50k
  int ReadBorder=Min(BlockBorder,DataBorder);
562
563
7.03M
  while (true)
564
7.03M
  {
565
7.03M
    UnpPtr=WrapUp(UnpPtr);
566
    
567
7.03M
    FirstWinDone|=(PrevPtr>UnpPtr);
568
7.03M
    PrevPtr=UnpPtr;
569
570
7.03M
    if (D.Inp.InAddr>=ReadBorder)
571
13.0k
    {
572
13.0k
      if (D.Inp.InAddr>BlockBorder || D.Inp.InAddr==BlockBorder && 
573
13.0k
          D.Inp.InBit>=D.BlockHeader.BlockBitSize)
574
0
        break;
575
576
      // If we do not have any more data in file to read, we must process
577
      // what we have until last byte. Otherwise we can return and append
578
      // more data to unprocessed few bytes.
579
13.0k
      if ((D.Inp.InAddr>=DataBorder) && !D.NoDataLeft || D.Inp.InAddr>=D.DataSize)
580
1.46k
      {
581
1.46k
        D.Incomplete=true;
582
1.46k
        break;
583
1.46k
      }
584
13.0k
    }
585
7.03M
    if (WrapDown(WriteBorder-UnpPtr)<=MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
586
3.02k
    {
587
3.02k
      UnpWriteBuf();
588
3.02k
      if (WrittenFileSize>DestUnpSize)
589
38
        return false;
590
3.02k
    }
591
592
7.03M
    uint MainSlot=DecodeNumber(D.Inp,&D.BlockTables.LD);
593
7.03M
    if (MainSlot<256)
594
4.86M
    {
595
4.86M
      Window[UnpPtr++]=(byte)MainSlot;
596
4.86M
      continue;
597
4.86M
    }
598
2.16M
    if (MainSlot>=262)
599
1.48M
    {
600
1.48M
      uint Length=SlotToLength(D.Inp,MainSlot-262);
601
602
1.48M
      size_t Distance=1;
603
1.48M
      uint DBits,DistSlot=DecodeNumber(D.Inp,&D.BlockTables.DD);
604
1.48M
      if (DistSlot<4)
605
879k
      {
606
879k
        DBits=0;
607
879k
        Distance+=DistSlot;
608
879k
      }
609
603k
      else
610
603k
      {
611
603k
        DBits=DistSlot/2 - 1;
612
603k
        Distance+=size_t(2 | (DistSlot & 1)) << DBits;
613
603k
      }
614
615
1.48M
      if (DBits>0)
616
603k
      {
617
603k
        if (DBits>=4)
618
470k
        {
619
470k
          if (DBits>4)
620
284k
          {
621
            // It is also possible to always use getbits64() here.
622
284k
            if (DBits>36)
623
8.14k
              Distance+=( ( size_t(D.Inp.getbits64() ) >> (68-DBits) ) << 4 );
624
276k
            else
625
276k
              Distance+=( ( size_t(D.Inp.getbits32() ) >> (36-DBits) ) << 4 );
626
284k
            D.Inp.addbits(DBits-4);
627
284k
          }
628
470k
          uint LowDist=DecodeNumber(D.Inp,&D.BlockTables.LDD);
629
470k
          Distance+=LowDist;
630
631
          // Distance can be 0 for multiples of 4 GB as result of size_t
632
          // overflow in 32-bit build. Its lower 32-bit can also erroneously
633
          // fit into dictionary after truncating upper 32-bits. Replace such
634
          // invalid distances with -1, so CopyString sets 0 data for them.
635
          // DBits>=30 also as DistSlot>=62 indicate distances >=0x80000001.
636
470k
          if (sizeof(Distance)==4 && DBits>=30)
637
0
            Distance=(size_t)-1;
638
470k
        }
639
133k
        else
640
133k
        {
641
133k
          Distance+=D.Inp.getbits32()>>(32-DBits);
642
133k
          D.Inp.addbits(DBits);
643
133k
        }
644
603k
      }
645
646
1.48M
      if (Distance>0x100)
647
275k
      {
648
275k
        Length++;
649
275k
        if (Distance>0x2000)
650
237k
        {
651
237k
          Length++;
652
237k
          if (Distance>0x40000)
653
113k
            Length++;
654
237k
        }
655
275k
      }
656
657
1.48M
      InsertOldDist(Distance);
658
1.48M
      LastLength=Length;
659
1.48M
      CopyString(Length,Distance);
660
1.48M
      continue;
661
1.48M
    }
662
678k
    if (MainSlot==256)
663
435k
    {
664
435k
      UnpackFilter Filter;
665
435k
      if (!ReadFilter(D.Inp,Filter) || !AddFilter(Filter))
666
0
        break;
667
435k
      continue;
668
435k
    }
669
243k
    if (MainSlot==257)
670
100k
    {
671
100k
      if (LastLength!=0)
672
15.3k
        CopyString(LastLength,OldDist[0]);
673
100k
      continue;
674
100k
    }
675
142k
    if (MainSlot<262)
676
142k
    {
677
142k
      uint DistNum=MainSlot-258;
678
142k
      size_t Distance=OldDist[DistNum];
679
463k
      for (uint I=DistNum;I>0;I--)
680
320k
        OldDist[I]=OldDist[I-1];
681
142k
      OldDist[0]=Distance;
682
683
142k
      uint LengthSlot=DecodeNumber(D.Inp,&D.BlockTables.RD);
684
142k
      uint Length=SlotToLength(D.Inp,LengthSlot);
685
142k
      LastLength=Length;
686
142k
      CopyString(Length,Distance);
687
142k
      continue;
688
142k
    }
689
142k
  }
690
1.46k
  return true;
691
1.50k
}