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