Coverage Report

Created: 2025-04-11 06:56

/src/unrar/unpack50frag.cpp
Line
Count
Source (jump to first uncovered line)
1
FragmentedWindow::FragmentedWindow()
2
12.7k
{
3
12.7k
  memset(Mem,0,sizeof(Mem));
4
12.7k
  memset(MemSize,0,sizeof(MemSize));
5
12.7k
  LastAllocated=0;
6
12.7k
}
7
8
9
FragmentedWindow::~FragmentedWindow()
10
12.7k
{
11
12.7k
  Reset();
12
12.7k
}
13
14
15
void FragmentedWindow::Reset()
16
12.7k
{
17
12.7k
  LastAllocated=0;
18
422k
  for (uint I=0;I<ASIZE(Mem);I++)
19
409k
    if (Mem[I]!=NULL)
20
0
    {
21
0
      free(Mem[I]);
22
0
      Mem[I]=NULL;
23
0
    }
24
12.7k
}
25
26
27
void FragmentedWindow::Init(size_t WinSize)
28
0
{
29
0
  Reset();
30
31
0
  uint BlockNum=0;
32
0
  size_t TotalSize=0; // Already allocated.
33
0
  while (TotalSize<WinSize && BlockNum<ASIZE(Mem))
34
0
  {
35
0
    size_t Size=WinSize-TotalSize; // Size needed to allocate.
36
37
    // Minimum still acceptable block size. Next allocations cannot be larger
38
    // than current, so we do not need blocks if they are smaller than
39
    // "size left / attempts left". Also we do not waste time to blocks
40
    // smaller than some arbitrary constant.
41
0
    size_t MinSize=Max(Size/(ASIZE(Mem)-BlockNum), 0x400000);
42
43
0
    byte *NewMem=NULL;
44
0
    while (Size>=MinSize)
45
0
    {
46
0
      NewMem=(byte *)malloc(Size);
47
0
      if (NewMem!=NULL)
48
0
        break;
49
0
      Size-=Size/32;
50
0
    }
51
0
    if (NewMem==NULL)
52
0
      throw std::bad_alloc();
53
54
    // Clean the window to generate the same output when unpacking corrupt
55
    // RAR files, which may access to unused areas of sliding dictionary.
56
0
    memset(NewMem,0,Size);
57
58
0
    Mem[BlockNum]=NewMem;
59
0
    TotalSize+=Size;
60
0
    MemSize[BlockNum]=TotalSize;
61
0
    BlockNum++;
62
0
  }
63
0
  if (TotalSize<WinSize) // Not found enough free blocks.
64
0
    throw std::bad_alloc();
65
0
  LastAllocated=WinSize;
66
0
}
67
68
69
byte& FragmentedWindow::operator [](size_t Item)
70
0
{
71
0
  if (Item<MemSize[0])
72
0
    return Mem[0][Item];
73
0
  for (uint I=1;I<ASIZE(MemSize);I++)
74
0
    if (Item<MemSize[I])
75
0
      return Mem[I][Item-MemSize[I-1]];
76
0
  return Mem[0][0]; // Must never happen;
77
0
}
78
79
80
void FragmentedWindow::CopyString(uint Length,size_t Distance,size_t &UnpPtr,bool FirstWinDone,size_t MaxWinSize)
81
0
{
82
0
  size_t SrcPtr=UnpPtr-Distance;
83
0
  if (Distance>UnpPtr)
84
0
  {
85
0
    SrcPtr+=MaxWinSize;
86
87
0
    if (Distance>MaxWinSize || !FirstWinDone)
88
0
    {
89
0
      while (Length-- > 0)
90
0
      {
91
0
        (*this)[UnpPtr]=0;
92
0
        if (++UnpPtr>=MaxWinSize)
93
0
          UnpPtr-=MaxWinSize;
94
0
      }
95
0
      return;
96
0
    }
97
0
  }
98
99
0
  while (Length-- > 0)
100
0
  {
101
0
    (*this)[UnpPtr]=(*this)[SrcPtr];
102
0
    if (++SrcPtr>=MaxWinSize)
103
0
      SrcPtr-=MaxWinSize;
104
0
    if (++UnpPtr>=MaxWinSize)
105
0
      UnpPtr-=MaxWinSize;
106
0
  }
107
0
}
108
109
110
void FragmentedWindow::CopyData(byte *Dest,size_t WinPos,size_t Size)
111
0
{
112
0
  for (size_t I=0;I<Size;I++)
113
0
    Dest[I]=(*this)[WinPos+I];
114
0
}
115
116
117
size_t FragmentedWindow::GetBlockSize(size_t StartPos,size_t RequiredSize)
118
0
{
119
0
  for (uint I=0;I<ASIZE(MemSize);I++)
120
0
    if (StartPos<MemSize[I])
121
0
      return Min(MemSize[I]-StartPos,RequiredSize);
122
0
  return 0; // Must never be here.
123
0
}