/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 | } |