| 23 | |
| 24 | |
| 25 | void FragmentedWindow::Init(size_t WinSize) |
| 26 | { |
| 27 | Reset(); |
| 28 | |
| 29 | uint BlockNum=0; |
| 30 | size_t TotalSize=0; // Already allocated. |
| 31 | while (TotalSize<WinSize && BlockNum<ASIZE(Mem)) |
| 32 | { |
| 33 | size_t Size=WinSize-TotalSize; // Size needed to allocate. |
| 34 | |
| 35 | // Minimum still acceptable block size. Next allocations cannot be larger |
| 36 | // than current, so we do not need blocks if they are smaller than |
| 37 | // "size left / attempts left". Also we do not waste time to blocks |
| 38 | // smaller than some arbitrary constant. |
| 39 | size_t MinSize=Max(Size/(ASIZE(Mem)-BlockNum), 0x400000); |
| 40 | |
| 41 | byte *NewMem=NULL; |
| 42 | while (Size>=MinSize) |
| 43 | { |
| 44 | NewMem=(byte *)malloc(Size); |
| 45 | if (NewMem!=NULL) |
| 46 | break; |
| 47 | Size-=Size/32; |
| 48 | } |
| 49 | if (NewMem==NULL) |
| 50 | throw std::bad_alloc(); |
| 51 | |
| 52 | // Clean the window to generate the same output when unpacking corrupt |
| 53 | // RAR files, which may access to unused areas of sliding dictionary. |
| 54 | memset(NewMem,0,Size); |
| 55 | |
| 56 | Mem[BlockNum]=NewMem; |
| 57 | TotalSize+=Size; |
| 58 | MemSize[BlockNum]=TotalSize; |
| 59 | BlockNum++; |
| 60 | } |
| 61 | if (TotalSize<WinSize) // Not found enough free blocks. |
| 62 | throw std::bad_alloc(); |
| 63 | } |
| 64 | |
| 65 | |
| 66 | byte& FragmentedWindow::operator [](size_t Item) |
nothing calls this directly
no outgoing calls
no test coverage detected