Coverage Report

Created: 2025-04-11 06:56

/src/unrar/unpackinline.cpp
Line
Count
Source
1
_forceinline void Unpack::InsertOldDist(size_t Distance)
2
4.02M
{
3
4.02M
  OldDist[3]=OldDist[2];
4
4.02M
  OldDist[2]=OldDist[1];
5
4.02M
  OldDist[1]=OldDist[0];
6
4.02M
  OldDist[0]=Distance;
7
4.02M
}
8
9
#if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED)
10
#define UNPACK_COPY8 // We can copy 8 bytes at any position as uint64.
11
#endif
12
13
_forceinline void Unpack::CopyString(uint Length,size_t Distance)
14
46.7M
{
15
46.7M
  size_t SrcPtr=UnpPtr-Distance;
16
17
  // Perform the correction here instead of "else", so matches crossing
18
  // the window beginning can also be processed by first "if" part.
19
46.7M
  if (Distance>UnpPtr) // Unlike SrcPtr>=MaxWinSize, it catches invalid distances like 0xfffffff0 in 32-bit build.
20
2.62M
  {
21
    // Same as WrapDown(SrcPtr), needed because of UnpPtr-Distance above.
22
    // We need the same condition below, so we expanded WrapDown() here.
23
2.62M
    SrcPtr+=MaxWinSize;
24
25
    // About Distance>MaxWinSize check.
26
    // SrcPtr can be >=MaxWinSize if distance exceeds MaxWinSize
27
    // in a malformed archive. Our WrapDown replacement above might not
28
    // correct it, so to prevent out of bound Window read we check it here.
29
    // Unlike SrcPtr>=MaxWinSize check, it allows MaxWinSize>0x80000000
30
    // in 32-bit build, which could cause overflow in SrcPtr.
31
    // About !FirstWinDone check.
32
    // If first window hasn't filled yet and it points outside of window,
33
    // set data to 0 instead of copying preceding file data, so result doesn't
34
    // depend on previously extracted files in non-solid archive.
35
2.62M
    if (Distance>MaxWinSize || !FirstWinDone)
36
2.60M
    {
37
      // Fill area of specified length with 0 instead of returning.
38
      // So if only the distance is broken and rest of packed data is valid,
39
      // it preserves offsets and allows to continue extraction.
40
      // If we set SrcPtr to random offset instead, let's say, 0,
41
      // we still will be copying preceding file data if UnpPtr is also 0.
42
944M
      while (Length-- > 0)
43
941M
      {
44
941M
        Window[UnpPtr]=0;
45
941M
        UnpPtr=WrapUp(UnpPtr+1);
46
941M
      }
47
2.60M
      return;
48
2.60M
    }
49
2.62M
  }
50
51
44.1M
  if (SrcPtr<MaxWinSize-MAX_INC_LZ_MATCH && UnpPtr<MaxWinSize-MAX_INC_LZ_MATCH)
52
43.4M
  {
53
    // If we are not close to end of window, we do not need to waste time
54
    // to WrapUp and WrapDown position protection.
55
56
43.4M
    byte *Src=Window+SrcPtr;
57
43.4M
    byte *Dest=Window+UnpPtr;
58
43.4M
    UnpPtr+=Length;
59
60
43.4M
#ifdef UNPACK_COPY8
61
43.4M
    if (Distance<Length) // Overlapping strings
62
42.9M
#endif
63
1.52G
      while (Length>=8)
64
1.48G
      {
65
1.48G
        Dest[0]=Src[0];
66
1.48G
        Dest[1]=Src[1];
67
1.48G
        Dest[2]=Src[2];
68
1.48G
        Dest[3]=Src[3];
69
1.48G
        Dest[4]=Src[4];
70
1.48G
        Dest[5]=Src[5];
71
1.48G
        Dest[6]=Src[6];
72
1.48G
        Dest[7]=Src[7];
73
74
1.48G
        Src+=8;
75
1.48G
        Dest+=8;
76
1.48G
        Length-=8;
77
1.48G
      }
78
530k
#ifdef UNPACK_COPY8
79
530k
    else
80
34.0M
      while (Length>=8)
81
33.4M
      {
82
        // In theory we still could overlap here.
83
        // Supposing Distance == MaxWinSize - 1 we have memcpy(Src, Src + 1, 8).
84
        // But for real RAR archives Distance <= MaxWinSize - MAX_INC_LZ_MATCH
85
        // always, so overlap here is impossible.
86
87
33.4M
        RawPut8(RawGet8(Src),Dest);
88
89
33.4M
        Src+=8;
90
33.4M
        Dest+=8;
91
33.4M
        Length-=8;
92
33.4M
      }
93
43.4M
#endif
94
95
    // Unroll the loop for 0 - 7 bytes left. Note that we use nested "if"s.
96
43.4M
    if (Length>0) { Dest[0]=Src[0];
97
41.4M
    if (Length>1) { Dest[1]=Src[1];
98
40.2M
    if (Length>2) { Dest[2]=Src[2];
99
36.3M
    if (Length>3) { Dest[3]=Src[3];
100
14.1M
    if (Length>4) { Dest[4]=Src[4];
101
13.4M
    if (Length>5) { Dest[5]=Src[5];
102
7.79M
    if (Length>6) { Dest[6]=Src[6]; } } } } } } } // Close all nested "if"s.
103
43.4M
  }
104
667k
  else
105
153M
    while (Length-- > 0) // Slow copying with all possible precautions.
106
153M
    {
107
153M
      Window[UnpPtr]=Window[WrapUp(SrcPtr++)];
108
      // We need to have masked UnpPtr after quit from loop, so it must not
109
      // be replaced with 'Window[WrapUp(UnpPtr++)]'
110
153M
      UnpPtr=WrapUp(UnpPtr+1);
111
153M
    }
112
44.1M
}
113
114
115
_forceinline uint Unpack::DecodeNumber(BitInput &Inp,DecodeTable *Dec)
116
99.5M
{
117
  // Left aligned 15 bit length raw bit field.
118
99.5M
  uint BitField=Inp.getbits() & 0xfffe;
119
120
99.5M
  if (BitField<Dec->DecodeLen[Dec->QuickBits])
121
93.3M
  {
122
93.3M
    uint Code=BitField>>(16-Dec->QuickBits);
123
93.3M
    Inp.addbits(Dec->QuickLen[Code]);
124
93.3M
    return Dec->QuickNum[Code];
125
93.3M
  }
126
127
  // Detect the real bit length for current code.
128
6.27M
  uint Bits=15;
129
48.4M
  for (uint I=Dec->QuickBits+1;I<15;I++)
130
42.8M
    if (BitField<Dec->DecodeLen[I])
131
684k
    {
132
684k
      Bits=I;
133
684k
      break;
134
684k
    }
135
136
6.27M
  Inp.addbits(Bits);
137
  
138
  // Calculate the distance from the start code for current bit length.
139
6.27M
  uint Dist=BitField-Dec->DecodeLen[Bits-1];
140
141
  // Start codes are left aligned, but we need the normal right aligned
142
  // number. So we shift the distance to the right.
143
6.27M
  Dist>>=(16-Bits);
144
145
  // Now we can calculate the position in the code list. It is the sum
146
  // of first position for current bit length and right aligned distance
147
  // between our bit field and start code for current bit length.
148
6.27M
  uint Pos=Dec->DecodePos[Bits]+Dist;
149
150
  // Out of bounds safety check required for damaged archives.
151
6.27M
  if (Pos>=Dec->MaxNum)
152
5.11M
    Pos=0;
153
154
  // Convert the position in the code list to position in alphabet
155
  // and return it.
156
6.27M
  return Dec->DecodeNum[Pos];
157
99.5M
}
158
159
160
_forceinline uint Unpack::SlotToLength(BitInput &Inp,uint Slot)
161
1.72M
{
162
1.72M
  uint LBits,Length=2;
163
1.72M
  if (Slot<8)
164
267k
  {
165
267k
    LBits=0;
166
267k
    Length+=Slot;
167
267k
  }
168
1.45M
  else
169
1.45M
  {
170
1.45M
    LBits=Slot/4-1;
171
1.45M
    Length+=(4 | (Slot & 3)) << LBits;
172
1.45M
  }
173
174
1.72M
  if (LBits>0)
175
1.45M
  {
176
1.45M
    Length+=Inp.getbits()>>(16-LBits);
177
1.45M
    Inp.addbits(LBits);
178
1.45M
  }
179
1.72M
  return Length;
180
1.72M
}