summaryrefslogtreecommitdiffstats
path: root/other-licenses/7zstub/src/7zip/Compress/Branch/BranchX86.c
blob: 2d2c03d2d841ade49811299b943f13dd6025b10f (plain)
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
/* BranchX86.c */

#include "BranchX86.h"

/*
static int inline Test86MSByte(Byte b)
{
  return (b == 0 || b == 0xFF);
}
*/
#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)

const int kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};

/*
void x86_Convert_Init(UInt32 *prevMask, UInt32 *prevPos)
{
  *prevMask = 0;
  *prevPos = (UInt32)(-5);
}
*/

UInt32 x86_Convert(Byte *buffer, UInt32 endPos, UInt32 nowPos, 
    UInt32 *prevMask, UInt32 *prevPos, int encoding)
{
  UInt32 bufferPos = 0;
  UInt32 limit;

  if (endPos < 5)
    return 0;
  
  if (nowPos - *prevPos > 5)
    *prevPos = nowPos - 5;
  
  limit = endPos - 5;
  while(bufferPos <= limit)
  {
    Byte b = buffer[bufferPos];
    UInt32 offset;
    if (b != 0xE8 && b != 0xE9)
    {
      bufferPos++;
      continue;
    }
    offset = (nowPos + bufferPos - *prevPos);
    *prevPos = (nowPos + bufferPos);
    if (offset > 5)
      *prevMask = 0;
    else
    {
      UInt32 i;
      for (i = 0; i < offset; i++)
      {
        *prevMask &= 0x77;
        *prevMask <<= 1;
      }
    }
    b = buffer[bufferPos + 4];
    if (Test86MSByte(b) && kMaskToAllowedStatus[(*prevMask >> 1) & 0x7] && 
      (*prevMask >> 1) < 0x10)
    {
      UInt32 src = 
        ((UInt32)(b) << 24) |
        ((UInt32)(buffer[bufferPos + 3]) << 16) |
        ((UInt32)(buffer[bufferPos + 2]) << 8) |
        (buffer[bufferPos + 1]);
      
      UInt32 dest;
      while(1)
      {
        UInt32 index;
        if (encoding)
          dest = (nowPos + bufferPos + 5) + src;
        else
          dest = src - (nowPos + bufferPos + 5);
        if (*prevMask == 0)
          break;
        index = kMaskToBitNumber[*prevMask >> 1];
        b = (Byte)(dest >> (24 - index * 8));
        if (!Test86MSByte(b))
          break;
        src = dest ^ ((1 << (32 - index * 8)) - 1);
      }
      buffer[bufferPos + 4] = (Byte)(~(((dest >> 24) & 1) - 1));
      buffer[bufferPos + 3] = (Byte)(dest >> 16);
      buffer[bufferPos + 2] = (Byte)(dest >> 8);
      buffer[bufferPos + 1] = (Byte)dest;
      bufferPos += 5;
      *prevMask = 0;
    }
    else
    {
      bufferPos++;
      *prevMask |= 1;
      if (Test86MSByte(b))
        *prevMask |= 0x10;
    }
  }
  return bufferPos;
}