/src/xz/src/liblzma/simple/x86.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: 0BSD |
2 | | |
3 | | /////////////////////////////////////////////////////////////////////////////// |
4 | | // |
5 | | /// \file x86.c |
6 | | /// \brief Filter for x86 binaries (BCJ filter) |
7 | | /// |
8 | | // Authors: Igor Pavlov |
9 | | // Lasse Collin |
10 | | // |
11 | | /////////////////////////////////////////////////////////////////////////////// |
12 | | |
13 | | #include "simple_private.h" |
14 | | |
15 | | |
16 | 0 | #define Test86MSByte(b) ((b) == 0 || (b) == 0xFF) |
17 | | |
18 | | |
19 | | typedef struct { |
20 | | uint32_t prev_mask; |
21 | | uint32_t prev_pos; |
22 | | } lzma_simple_x86; |
23 | | |
24 | | |
25 | | static size_t |
26 | | x86_code(void *simple_ptr, uint32_t now_pos, bool is_encoder, |
27 | | uint8_t *buffer, size_t size) |
28 | 0 | { |
29 | 0 | static const uint32_t MASK_TO_BIT_NUMBER[5] = { 0, 1, 2, 2, 3 }; |
30 | |
|
31 | 0 | lzma_simple_x86 *simple = simple_ptr; |
32 | 0 | uint32_t prev_mask = simple->prev_mask; |
33 | 0 | uint32_t prev_pos = simple->prev_pos; |
34 | |
|
35 | 0 | if (size < 5) |
36 | 0 | return 0; |
37 | | |
38 | 0 | if (now_pos - prev_pos > 5) |
39 | 0 | prev_pos = now_pos - 5; |
40 | |
|
41 | 0 | const size_t limit = size - 5; |
42 | 0 | size_t buffer_pos = 0; |
43 | |
|
44 | 0 | while (buffer_pos <= limit) { |
45 | 0 | uint8_t b = buffer[buffer_pos]; |
46 | 0 | if (b != 0xE8 && b != 0xE9) { |
47 | 0 | ++buffer_pos; |
48 | 0 | continue; |
49 | 0 | } |
50 | | |
51 | 0 | const uint32_t offset = now_pos + (uint32_t)(buffer_pos) |
52 | 0 | - prev_pos; |
53 | 0 | prev_pos = now_pos + (uint32_t)(buffer_pos); |
54 | |
|
55 | 0 | if (offset > 5) { |
56 | 0 | prev_mask = 0; |
57 | 0 | } else { |
58 | 0 | for (uint32_t i = 0; i < offset; ++i) { |
59 | 0 | prev_mask &= 0x77; |
60 | 0 | prev_mask <<= 1; |
61 | 0 | } |
62 | 0 | } |
63 | |
|
64 | 0 | b = buffer[buffer_pos + 4]; |
65 | |
|
66 | 0 | if (Test86MSByte(b) && (prev_mask >> 1) <= 4 |
67 | 0 | && (prev_mask >> 1) != 3) { |
68 | |
|
69 | 0 | uint32_t src = ((uint32_t)(b) << 24) |
70 | 0 | | ((uint32_t)(buffer[buffer_pos + 3]) << 16) |
71 | 0 | | ((uint32_t)(buffer[buffer_pos + 2]) << 8) |
72 | 0 | | (buffer[buffer_pos + 1]); |
73 | |
|
74 | 0 | uint32_t dest; |
75 | 0 | while (true) { |
76 | 0 | if (is_encoder) |
77 | 0 | dest = src + (now_pos + (uint32_t)( |
78 | 0 | buffer_pos) + 5); |
79 | 0 | else |
80 | 0 | dest = src - (now_pos + (uint32_t)( |
81 | 0 | buffer_pos) + 5); |
82 | |
|
83 | 0 | if (prev_mask == 0) |
84 | 0 | break; |
85 | | |
86 | 0 | const uint32_t i = MASK_TO_BIT_NUMBER[ |
87 | 0 | prev_mask >> 1]; |
88 | |
|
89 | 0 | b = (uint8_t)(dest >> (24 - i * 8)); |
90 | |
|
91 | 0 | if (!Test86MSByte(b)) |
92 | 0 | break; |
93 | | |
94 | 0 | src = dest ^ ((1U << (32 - i * 8)) - 1); |
95 | 0 | } |
96 | |
|
97 | 0 | buffer[buffer_pos + 4] |
98 | 0 | = (uint8_t)(~(((dest >> 24) & 1) - 1)); |
99 | 0 | buffer[buffer_pos + 3] = (uint8_t)(dest >> 16); |
100 | 0 | buffer[buffer_pos + 2] = (uint8_t)(dest >> 8); |
101 | 0 | buffer[buffer_pos + 1] = (uint8_t)(dest); |
102 | 0 | buffer_pos += 5; |
103 | 0 | prev_mask = 0; |
104 | |
|
105 | 0 | } else { |
106 | 0 | ++buffer_pos; |
107 | 0 | prev_mask |= 1; |
108 | 0 | if (Test86MSByte(b)) |
109 | 0 | prev_mask |= 0x10; |
110 | 0 | } |
111 | 0 | } |
112 | |
|
113 | 0 | simple->prev_mask = prev_mask; |
114 | 0 | simple->prev_pos = prev_pos; |
115 | |
|
116 | 0 | return buffer_pos; |
117 | 0 | } |
118 | | |
119 | | |
120 | | static lzma_ret |
121 | | x86_coder_init(lzma_next_coder *next, const lzma_allocator *allocator, |
122 | | const lzma_filter_info *filters, bool is_encoder) |
123 | 0 | { |
124 | 0 | const lzma_ret ret = lzma_simple_coder_init(next, allocator, filters, |
125 | 0 | &x86_code, sizeof(lzma_simple_x86), 5, 1, is_encoder); |
126 | |
|
127 | 0 | if (ret == LZMA_OK) { |
128 | 0 | lzma_simple_coder *coder = next->coder; |
129 | 0 | lzma_simple_x86 *simple = coder->simple; |
130 | 0 | simple->prev_mask = 0; |
131 | 0 | simple->prev_pos = (uint32_t)(-5); |
132 | 0 | } |
133 | |
|
134 | 0 | return ret; |
135 | 0 | } |
136 | | |
137 | | |
138 | | #ifdef HAVE_ENCODER_X86 |
139 | | extern lzma_ret |
140 | | lzma_simple_x86_encoder_init(lzma_next_coder *next, |
141 | | const lzma_allocator *allocator, |
142 | | const lzma_filter_info *filters) |
143 | 0 | { |
144 | 0 | return x86_coder_init(next, allocator, filters, true); |
145 | 0 | } |
146 | | |
147 | | |
148 | | extern LZMA_API(size_t) |
149 | | lzma_bcj_x86_encode(uint32_t start_offset, uint8_t *buf, size_t size) |
150 | 0 | { |
151 | 0 | lzma_simple_x86 simple = { |
152 | 0 | .prev_mask = 0, |
153 | 0 | .prev_pos = (uint32_t)(-5), |
154 | 0 | }; |
155 | |
|
156 | 0 | return x86_code(&simple, start_offset, true, buf, size); |
157 | 0 | } |
158 | | #endif |
159 | | |
160 | | |
161 | | #ifdef HAVE_DECODER_X86 |
162 | | extern lzma_ret |
163 | | lzma_simple_x86_decoder_init(lzma_next_coder *next, |
164 | | const lzma_allocator *allocator, |
165 | | const lzma_filter_info *filters) |
166 | 0 | { |
167 | 0 | return x86_coder_init(next, allocator, filters, false); |
168 | 0 | } |
169 | | |
170 | | |
171 | | extern LZMA_API(size_t) |
172 | | lzma_bcj_x86_decode(uint32_t start_offset, uint8_t *buf, size_t size) |
173 | 0 | { |
174 | 0 | lzma_simple_x86 simple = { |
175 | 0 | .prev_mask = 0, |
176 | 0 | .prev_pos = (uint32_t)(-5), |
177 | 0 | }; |
178 | |
|
179 | | return x86_code(&simple, start_offset, false, buf, size); |
180 | 0 | } |
181 | | #endif |