File: unpack50frag.cpp

package info (click to toggle)
unrar-nonfree 1%3A7.1.8-1
  • links: PTS, VCS
  • area: non-free
  • in suites: trixie
  • size: 1,952 kB
  • sloc: cpp: 26,394; makefile: 712; sh: 11
file content (123 lines) | stat: -rw-r--r-- 2,730 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
FragmentedWindow::FragmentedWindow()
{
  memset(Mem,0,sizeof(Mem));
  memset(MemSize,0,sizeof(MemSize));
  LastAllocated=0;
}


FragmentedWindow::~FragmentedWindow()
{
  Reset();
}


void FragmentedWindow::Reset()
{
  LastAllocated=0;
  for (uint I=0;I<ASIZE(Mem);I++)
    if (Mem[I]!=NULL)
    {
      free(Mem[I]);
      Mem[I]=NULL;
    }
}


void FragmentedWindow::Init(size_t WinSize)
{
  Reset();

  uint BlockNum=0;
  size_t TotalSize=0; // Already allocated.
  while (TotalSize<WinSize && BlockNum<ASIZE(Mem))
  {
    size_t Size=WinSize-TotalSize; // Size needed to allocate.

    // Minimum still acceptable block size. Next allocations cannot be larger
    // than current, so we do not need blocks if they are smaller than
    // "size left / attempts left". Also we do not waste time to blocks
    // smaller than some arbitrary constant.
    size_t MinSize=Max(Size/(ASIZE(Mem)-BlockNum), 0x400000);

    byte *NewMem=NULL;
    while (Size>=MinSize)
    {
      NewMem=(byte *)malloc(Size);
      if (NewMem!=NULL)
        break;
      Size-=Size/32;
    }
    if (NewMem==NULL)
      throw std::bad_alloc();

    // Clean the window to generate the same output when unpacking corrupt
    // RAR files, which may access to unused areas of sliding dictionary.
    memset(NewMem,0,Size);

    Mem[BlockNum]=NewMem;
    TotalSize+=Size;
    MemSize[BlockNum]=TotalSize;
    BlockNum++;
  }
  if (TotalSize<WinSize) // Not found enough free blocks.
    throw std::bad_alloc();
  LastAllocated=WinSize;
}


byte& FragmentedWindow::operator [](size_t Item)
{
  if (Item<MemSize[0])
    return Mem[0][Item];
  for (uint I=1;I<ASIZE(MemSize);I++)
    if (Item<MemSize[I])
      return Mem[I][Item-MemSize[I-1]];
  return Mem[0][0]; // Must never happen;
}


void FragmentedWindow::CopyString(uint Length,size_t Distance,size_t &UnpPtr,bool FirstWinDone,size_t MaxWinSize)
{
  size_t SrcPtr=UnpPtr-Distance;
  if (Distance>UnpPtr)
  {
    SrcPtr+=MaxWinSize;

    if (Distance>MaxWinSize || !FirstWinDone)
    {
      while (Length-- > 0)
      {
        (*this)[UnpPtr]=0;
        if (++UnpPtr>=MaxWinSize)
          UnpPtr-=MaxWinSize;
      }
      return;
    }
  }

  while (Length-- > 0)
  {
    (*this)[UnpPtr]=(*this)[SrcPtr];
    if (++SrcPtr>=MaxWinSize)
      SrcPtr-=MaxWinSize;
    if (++UnpPtr>=MaxWinSize)
      UnpPtr-=MaxWinSize;
  }
}


void FragmentedWindow::CopyData(byte *Dest,size_t WinPos,size_t Size)
{
  for (size_t I=0;I<Size;I++)
    Dest[I]=(*this)[WinPos+I];
}


size_t FragmentedWindow::GetBlockSize(size_t StartPos,size_t RequiredSize)
{
  for (uint I=0;I<ASIZE(MemSize);I++)
    if (StartPos<MemSize[I])
      return Min(MemSize[I]-StartPos,RequiredSize);
  return 0; // Must never be here.
}