unpack50frag.cpp 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. FragmentedWindow::FragmentedWindow()
  2. {
  3. memset(Mem,0,sizeof(Mem));
  4. memset(MemSize,0,sizeof(MemSize));
  5. }
  6. FragmentedWindow::~FragmentedWindow()
  7. {
  8. Reset();
  9. }
  10. void FragmentedWindow::Reset()
  11. {
  12. for (uint I=0;I<ASIZE(Mem);I++)
  13. if (Mem[I]!=NULL)
  14. {
  15. free(Mem[I]);
  16. Mem[I]=NULL;
  17. }
  18. }
  19. void FragmentedWindow::Init(size_t WinSize)
  20. {
  21. Reset();
  22. uint BlockNum=0;
  23. size_t TotalSize=0; // Already allocated.
  24. while (TotalSize<WinSize && BlockNum<ASIZE(Mem))
  25. {
  26. size_t Size=WinSize-TotalSize; // Size needed to allocate.
  27. // Minimum still acceptable block size. Next allocations cannot be larger
  28. // than current, so we do not need blocks if they are smaller than
  29. // "size left / attempts left". Also we do not waste time to blocks
  30. // smaller than some arbitrary constant.
  31. size_t MinSize=Max(Size/(ASIZE(Mem)-BlockNum), 0x400000);
  32. byte *NewMem=NULL;
  33. while (Size>=MinSize)
  34. {
  35. NewMem=(byte *)malloc(Size);
  36. if (NewMem!=NULL)
  37. break;
  38. Size-=Size/32;
  39. }
  40. if (NewMem==NULL)
  41. throw std::bad_alloc();
  42. // Clean the window to generate the same output when unpacking corrupt
  43. // RAR files, which may access to unused areas of sliding dictionary.
  44. memset(NewMem,0,Size);
  45. Mem[BlockNum]=NewMem;
  46. TotalSize+=Size;
  47. MemSize[BlockNum]=TotalSize;
  48. BlockNum++;
  49. }
  50. if (TotalSize<WinSize) // Not found enough free blocks.
  51. throw std::bad_alloc();
  52. }
  53. byte& FragmentedWindow::operator [](size_t Item)
  54. {
  55. if (Item<MemSize[0])
  56. return Mem[0][Item];
  57. for (uint I=1;I<ASIZE(MemSize);I++)
  58. if (Item<MemSize[I])
  59. return Mem[I][Item-MemSize[I-1]];
  60. return Mem[0][0]; // Must never happen;
  61. }
  62. void FragmentedWindow::CopyString(uint Length,uint Distance,size_t &UnpPtr,size_t MaxWinMask)
  63. {
  64. size_t SrcPtr=UnpPtr-Distance;
  65. while (Length-- > 0)
  66. {
  67. (*this)[UnpPtr]=(*this)[SrcPtr++ & MaxWinMask];
  68. // We need to have masked UnpPtr after quit from loop, so it must not
  69. // be replaced with '(*this)[UnpPtr++ & MaxWinMask]'
  70. UnpPtr=(UnpPtr+1) & MaxWinMask;
  71. }
  72. }
  73. void FragmentedWindow::CopyData(byte *Dest,size_t WinPos,size_t Size)
  74. {
  75. for (size_t I=0;I<Size;I++)
  76. Dest[I]=(*this)[WinPos+I];
  77. }
  78. size_t FragmentedWindow::GetBlockSize(size_t StartPos,size_t RequiredSize)
  79. {
  80. for (uint I=0;I<ASIZE(MemSize);I++)
  81. if (StartPos<MemSize[I])
  82. return Min(MemSize[I]-StartPos,RequiredSize);
  83. return 0; // Must never be here.
  84. }