Line | Count | Source |
1 | | /*************************************************************************************************** |
2 | | |
3 | | Zyan Disassembler Library (Zydis) |
4 | | |
5 | | Original Author : Florian Bernd, Joel Hoener |
6 | | |
7 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
8 | | * of this software and associated documentation files (the "Software"), to deal |
9 | | * in the Software without restriction, including without limitation the rights |
10 | | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
11 | | * copies of the Software, and to permit persons to whom the Software is |
12 | | * furnished to do so, subject to the following conditions: |
13 | | * |
14 | | * The above copyright notice and this permission notice shall be included in all |
15 | | * copies or substantial portions of the Software. |
16 | | * |
17 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
18 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
19 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
20 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
21 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
22 | | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
23 | | * SOFTWARE. |
24 | | |
25 | | ***************************************************************************************************/ |
26 | | |
27 | | #include <Zydis/Internal/String.h> |
28 | | |
29 | | /* ============================================================================================== */ |
30 | | /* Constants */ |
31 | | /* ============================================================================================== */ |
32 | | |
33 | | /* ---------------------------------------------------------------------------------------------- */ |
34 | | /* Defines */ |
35 | | /* ---------------------------------------------------------------------------------------------- */ |
36 | | |
37 | | #define ZYDIS_MAXCHARS_DEC_32 10 |
38 | 3.19k | #define ZYDIS_MAXCHARS_DEC_64 20 |
39 | 1.20k | #define ZYDIS_MAXCHARS_HEX_32 8 |
40 | 452 | #define ZYDIS_MAXCHARS_HEX_64 16 |
41 | | |
42 | | /* ---------------------------------------------------------------------------------------------- */ |
43 | | /* Lookup Tables */ |
44 | | /* ---------------------------------------------------------------------------------------------- */ |
45 | | |
46 | | static const char* const DECIMAL_LOOKUP = |
47 | | "00010203040506070809" |
48 | | "10111213141516171819" |
49 | | "20212223242526272829" |
50 | | "30313233343536373839" |
51 | | "40414243444546474849" |
52 | | "50515253545556575859" |
53 | | "60616263646566676869" |
54 | | "70717273747576777879" |
55 | | "80818283848586878889" |
56 | | "90919293949596979899"; |
57 | | |
58 | | /* ---------------------------------------------------------------------------------------------- */ |
59 | | |
60 | | /* ============================================================================================== */ |
61 | | /* Internal Functions */ |
62 | | /* ============================================================================================== */ |
63 | | |
64 | | /* ---------------------------------------------------------------------------------------------- */ |
65 | | /* Decimal */ |
66 | | /* ---------------------------------------------------------------------------------------------- */ |
67 | | |
68 | | #if ZYAN_ARCHITECTURE_WIDTH != 64 |
69 | | static ZyanStatus ZydisStringAppendDecU32(ZyanString* string, ZyanU32 value, ZyanU8 padding_length) |
70 | | { |
71 | | ZYAN_ASSERT(string); |
72 | | ZYAN_ASSERT(!string->vector.allocator); |
73 | | |
74 | | char buffer[ZYDIS_MAXCHARS_DEC_32]; |
75 | | char *buffer_end = &buffer[ZYDIS_MAXCHARS_DEC_32]; |
76 | | char *buffer_write_pointer = buffer_end; |
77 | | while (value >= 100) |
78 | | { |
79 | | const ZyanU32 value_old = value; |
80 | | buffer_write_pointer -= 2; |
81 | | value /= 100; |
82 | | ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[(value_old - (value * 100)) * 2], 2); |
83 | | } |
84 | | buffer_write_pointer -= 2; |
85 | | ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[value * 2], 2); |
86 | | |
87 | | const ZyanUSize offset_odd = (ZyanUSize)(value < 10); |
88 | | const ZyanUSize length_number = buffer_end - buffer_write_pointer - offset_odd; |
89 | | const ZyanUSize length_total = ZYAN_MAX(length_number, padding_length); |
90 | | const ZyanUSize length_target = string->vector.size; |
91 | | |
92 | | if (string->vector.size + length_total > string->vector.capacity) |
93 | | { |
94 | | return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; |
95 | | } |
96 | | |
97 | | ZyanUSize offset_write = 0; |
98 | | if (padding_length > length_number) |
99 | | { |
100 | | offset_write = padding_length - length_number; |
101 | | ZYAN_MEMSET((char*)string->vector.data + length_target - 1, '0', offset_write); |
102 | | } |
103 | | |
104 | | ZYAN_MEMCPY((char*)string->vector.data + length_target + offset_write - 1, |
105 | | buffer_write_pointer + offset_odd, length_number); |
106 | | string->vector.size = length_target + length_total; |
107 | | ZYDIS_STRING_NULLTERMINATE(string); |
108 | | |
109 | | return ZYAN_STATUS_SUCCESS; |
110 | | } |
111 | | #endif |
112 | | |
113 | | static ZyanStatus ZydisStringAppendDecU64(ZyanString* string, ZyanU64 value, ZyanU8 padding_length) |
114 | 3.19k | { |
115 | 3.19k | ZYAN_ASSERT(string); |
116 | 3.19k | ZYAN_ASSERT(!string->vector.allocator); |
117 | | |
118 | 3.19k | char buffer[ZYDIS_MAXCHARS_DEC_64]; |
119 | 3.19k | char *buffer_end = &buffer[ZYDIS_MAXCHARS_DEC_64]; |
120 | 3.19k | char *buffer_write_pointer = buffer_end; |
121 | 11.0k | while (value >= 100) |
122 | 7.85k | { |
123 | 7.85k | const ZyanU64 value_old = value; |
124 | 7.85k | buffer_write_pointer -= 2; |
125 | 7.85k | ZYAN_DIV64(value, 100); |
126 | 7.85k | ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[(value_old - (value * 100)) * 2], 2); |
127 | 7.85k | } |
128 | 3.19k | buffer_write_pointer -= 2; |
129 | 3.19k | ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[value * 2], 2); |
130 | | |
131 | 3.19k | const ZyanUSize offset_odd = (ZyanUSize)(value < 10); |
132 | 3.19k | const ZyanUSize length_number = buffer_end - buffer_write_pointer - offset_odd; |
133 | 3.19k | const ZyanUSize length_total = ZYAN_MAX(length_number, padding_length); |
134 | 3.19k | const ZyanUSize length_target = string->vector.size; |
135 | | |
136 | 3.19k | if (string->vector.size + length_total > string->vector.capacity) |
137 | 532 | { |
138 | 532 | return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; |
139 | 532 | } |
140 | | |
141 | 2.66k | ZyanUSize offset_write = 0; |
142 | 2.66k | if (padding_length > length_number) |
143 | 338 | { |
144 | 338 | offset_write = padding_length - length_number; |
145 | 338 | ZYAN_MEMSET((char*)string->vector.data + length_target - 1, '0', offset_write); |
146 | 338 | } |
147 | | |
148 | 2.66k | ZYAN_MEMCPY((char*)string->vector.data + length_target + offset_write - 1, |
149 | 2.66k | buffer_write_pointer + offset_odd, length_number); |
150 | 2.66k | string->vector.size = length_target + length_total; |
151 | 2.66k | ZYDIS_STRING_NULLTERMINATE(string); |
152 | | |
153 | 2.66k | return ZYAN_STATUS_SUCCESS; |
154 | 3.19k | } |
155 | | |
156 | | /* ---------------------------------------------------------------------------------------------- */ |
157 | | /* Hexadecimal */ |
158 | | /* ---------------------------------------------------------------------------------------------- */ |
159 | | |
160 | | #if ZYAN_ARCHITECTURE_WIDTH != 64 |
161 | | static ZyanStatus ZydisStringAppendHexU32(ZyanString* string, ZyanU32 value, ZyanU8 padding_length, |
162 | | ZyanBool force_leading_number, ZyanBool uppercase) |
163 | | { |
164 | | ZYAN_ASSERT(string); |
165 | | ZYAN_ASSERT(!string->vector.allocator); |
166 | | |
167 | | const ZyanUSize len = string->vector.size; |
168 | | const ZyanUSize remaining = string->vector.capacity - string->vector.size; |
169 | | |
170 | | if (remaining < (ZyanUSize)padding_length) |
171 | | { |
172 | | return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; |
173 | | } |
174 | | |
175 | | if (!value) |
176 | | { |
177 | | const ZyanU8 n = (padding_length ? padding_length : 1); |
178 | | |
179 | | if (remaining < (ZyanUSize)n) |
180 | | { |
181 | | return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; |
182 | | } |
183 | | |
184 | | ZYAN_MEMSET((char*)string->vector.data + len - 1, '0', n); |
185 | | string->vector.size = len + n; |
186 | | ZYDIS_STRING_NULLTERMINATE(string); |
187 | | |
188 | | return ZYAN_STATUS_SUCCESS; |
189 | | } |
190 | | |
191 | | ZyanU8 n = 0; |
192 | | char* buffer = ZYAN_NULL; |
193 | | for (ZyanI8 i = ZYDIS_MAXCHARS_HEX_32 - 1; i >= 0; --i) |
194 | | { |
195 | | const ZyanU8 v = (value >> i * 4) & 0x0F; |
196 | | if (!n) |
197 | | { |
198 | | if (!v) |
199 | | { |
200 | | continue; |
201 | | } |
202 | | const ZyanU8 zero = force_leading_number && (v > 9) && (padding_length <= i) ? 1 : 0; |
203 | | if (remaining <= (ZyanUSize)i + zero) |
204 | | { |
205 | | return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; |
206 | | } |
207 | | buffer = (char*)string->vector.data + len - 1; |
208 | | if (zero) |
209 | | { |
210 | | buffer[n++] = '0'; |
211 | | } |
212 | | if (padding_length > i) |
213 | | { |
214 | | n = padding_length - i - 1; |
215 | | ZYAN_MEMSET(buffer, '0', n); |
216 | | } |
217 | | } |
218 | | ZYAN_ASSERT(buffer); |
219 | | if (uppercase) |
220 | | { |
221 | | buffer[n++] = "0123456789ABCDEF"[v]; |
222 | | } else |
223 | | { |
224 | | buffer[n++] = "0123456789abcdef"[v]; |
225 | | } |
226 | | } |
227 | | string->vector.size = len + n; |
228 | | ZYDIS_STRING_NULLTERMINATE(string); |
229 | | |
230 | | return ZYAN_STATUS_SUCCESS; |
231 | | } |
232 | | #endif |
233 | | |
234 | | static ZyanStatus ZydisStringAppendHexU64(ZyanString* string, ZyanU64 value, ZyanU8 padding_length, |
235 | | ZyanBool force_leading_number, ZyanBool uppercase) |
236 | 2.17k | { |
237 | 2.17k | ZYAN_ASSERT(string); |
238 | 2.17k | ZYAN_ASSERT(!string->vector.allocator); |
239 | | |
240 | 2.17k | const ZyanUSize len = string->vector.size; |
241 | 2.17k | const ZyanUSize remaining = string->vector.capacity - string->vector.size; |
242 | | |
243 | 2.17k | if (remaining < (ZyanUSize)padding_length) |
244 | 417 | { |
245 | 417 | return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; |
246 | 417 | } |
247 | | |
248 | 1.75k | if (!value) |
249 | 102 | { |
250 | 102 | const ZyanU8 n = (padding_length ? padding_length : 1); |
251 | | |
252 | 102 | if (remaining < (ZyanUSize)n) |
253 | 8 | { |
254 | 8 | return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; |
255 | 8 | } |
256 | | |
257 | 94 | ZYAN_MEMSET((char*)string->vector.data + len - 1, '0', n); |
258 | 94 | string->vector.size = len + n; |
259 | 94 | ZYDIS_STRING_NULLTERMINATE(string); |
260 | | |
261 | 94 | return ZYAN_STATUS_SUCCESS; |
262 | 102 | } |
263 | | |
264 | 1.65k | ZyanU8 n = 0; |
265 | 1.65k | char* buffer = ZYAN_NULL; |
266 | 1.65k | for (ZyanI8 i = ((value & 0xFFFFFFFF00000000) ? |
267 | 16.6k | ZYDIS_MAXCHARS_HEX_64 : ZYDIS_MAXCHARS_HEX_32) - 1; i >= 0; --i) |
268 | 15.1k | { |
269 | 15.1k | const ZyanU8 v = (value >> i * 4) & 0x0F; |
270 | 15.1k | if (!n) |
271 | 6.98k | { |
272 | 6.98k | if (!v) |
273 | 5.32k | { |
274 | 5.32k | continue; |
275 | 5.32k | } |
276 | 1.65k | const ZyanU8 zero = force_leading_number && (v > 9) && (padding_length <= i) ? 1 : 0; |
277 | 1.65k | if (remaining <= (ZyanUSize)i + zero) |
278 | 150 | { |
279 | 150 | return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; |
280 | 150 | } |
281 | 1.50k | buffer = (char*)string->vector.data + len - 1; |
282 | 1.50k | if (zero) |
283 | 281 | { |
284 | 281 | buffer[n++] = '0'; |
285 | 281 | } |
286 | 1.50k | if (padding_length > i) |
287 | 734 | { |
288 | 734 | n = padding_length - i - 1; |
289 | 734 | ZYAN_MEMSET(buffer, '0', n); |
290 | 734 | } |
291 | 1.50k | } |
292 | 9.62k | ZYAN_ASSERT(buffer); |
293 | 9.62k | if (uppercase) |
294 | 7.17k | { |
295 | 7.17k | buffer[n++] = "0123456789ABCDEF"[v]; |
296 | 7.17k | } else |
297 | 2.44k | { |
298 | 2.44k | buffer[n++] = "0123456789abcdef"[v]; |
299 | 2.44k | } |
300 | 9.62k | } |
301 | 1.50k | string->vector.size = len + n; |
302 | 1.50k | ZYDIS_STRING_NULLTERMINATE(string); |
303 | | |
304 | 1.50k | return ZYAN_STATUS_SUCCESS; |
305 | 1.65k | } |
306 | | |
307 | | /* ---------------------------------------------------------------------------------------------- */ |
308 | | |
309 | | /* ============================================================================================== */ |
310 | | /* Public Functions */ |
311 | | /* ============================================================================================== */ |
312 | | |
313 | | /* ---------------------------------------------------------------------------------------------- */ |
314 | | /* Formatting */ |
315 | | /* ---------------------------------------------------------------------------------------------- */ |
316 | | |
317 | | ZyanStatus ZydisStringAppendDecU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length, |
318 | | const ZyanStringView* prefix, const ZyanStringView* suffix) |
319 | 3.26k | { |
320 | 3.26k | if (prefix) |
321 | 1.22k | { |
322 | 1.22k | ZYAN_CHECK(ZydisStringAppend(string, prefix)); |
323 | 1.22k | } |
324 | | |
325 | 3.19k | #if ZYAN_ARCHITECTURE_WIDTH == 64 |
326 | 3.19k | ZYAN_CHECK(ZydisStringAppendDecU64(string, value, padding_length)); |
327 | | #else |
328 | | if (value & 0xFFFFFFFF00000000) |
329 | | { |
330 | | ZYAN_CHECK(ZydisStringAppendDecU64(string, value, padding_length)); |
331 | | } |
332 | | ZYAN_CHECK(ZydisStringAppendDecU32(string, (ZyanU32)value, padding_length)); |
333 | | #endif |
334 | | |
335 | 2.66k | if (suffix) |
336 | 1.42k | { |
337 | 1.42k | return ZydisStringAppend(string, suffix); |
338 | 1.42k | } |
339 | 1.23k | return ZYAN_STATUS_SUCCESS; |
340 | 2.66k | } |
341 | | |
342 | | ZyanStatus ZydisStringAppendHexU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length, |
343 | | ZyanBool force_leading_number, ZyanBool uppercase, const ZyanStringView* prefix, |
344 | | const ZyanStringView* suffix) |
345 | 2.22k | { |
346 | 2.22k | if (prefix) |
347 | 1.08k | { |
348 | 1.08k | ZYAN_CHECK(ZydisStringAppend(string, prefix)); |
349 | 1.08k | } |
350 | | |
351 | 2.17k | #if ZYAN_ARCHITECTURE_WIDTH == 64 |
352 | 2.17k | ZYAN_CHECK(ZydisStringAppendHexU64(string, value, padding_length, force_leading_number, |
353 | 2.17k | uppercase)); |
354 | | #else |
355 | | if (value & 0xFFFFFFFF00000000) |
356 | | { |
357 | | ZYAN_CHECK(ZydisStringAppendHexU64(string, value, padding_length, force_leading_number, |
358 | | uppercase)); |
359 | | } |
360 | | else |
361 | | { |
362 | | ZYAN_CHECK(ZydisStringAppendHexU32(string, (ZyanU32)value, padding_length, |
363 | | force_leading_number, uppercase)); |
364 | | } |
365 | | #endif |
366 | | |
367 | 1.60k | if (suffix) |
368 | 1.06k | { |
369 | 1.06k | return ZydisStringAppend(string, suffix); |
370 | 1.06k | } |
371 | 538 | return ZYAN_STATUS_SUCCESS; |
372 | 1.60k | } |
373 | | |
374 | | /* ---------------------------------------------------------------------------------------------- */ |
375 | | |
376 | | /* ============================================================================================== */ |