Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/zydis/src/String.c
4211 views
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
#define ZYDIS_MAXCHARS_DEC_64 20
39
#define ZYDIS_MAXCHARS_HEX_32 8
40
#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 defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN) || defined(ZYAN_WASM) || defined(ZYAN_PPC)
69
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
ZyanStatus ZydisStringAppendDecU64(ZyanString* string, ZyanU64 value, ZyanU8 padding_length)
114
{
115
ZYAN_ASSERT(string);
116
ZYAN_ASSERT(!string->vector.allocator);
117
118
char buffer[ZYDIS_MAXCHARS_DEC_64];
119
char *buffer_end = &buffer[ZYDIS_MAXCHARS_DEC_64];
120
char *buffer_write_pointer = buffer_end;
121
while (value >= 100)
122
{
123
const ZyanU64 value_old = value;
124
buffer_write_pointer -= 2;
125
value /= 100;
126
ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[(value_old - (value * 100)) * 2], 2);
127
}
128
buffer_write_pointer -= 2;
129
ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[value * 2], 2);
130
131
const ZyanUSize offset_odd = (ZyanUSize)(value < 10);
132
const ZyanUSize length_number = buffer_end - buffer_write_pointer - offset_odd;
133
const ZyanUSize length_total = ZYAN_MAX(length_number, padding_length);
134
const ZyanUSize length_target = string->vector.size;
135
136
if (string->vector.size + length_total > string->vector.capacity)
137
{
138
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
139
}
140
141
ZyanUSize offset_write = 0;
142
if (padding_length > length_number)
143
{
144
offset_write = padding_length - length_number;
145
ZYAN_MEMSET((char*)string->vector.data + length_target - 1, '0', offset_write);
146
}
147
148
ZYAN_MEMCPY((char*)string->vector.data + length_target + offset_write - 1,
149
buffer_write_pointer + offset_odd, length_number);
150
string->vector.size = length_target + length_total;
151
ZYDIS_STRING_NULLTERMINATE(string);
152
153
return ZYAN_STATUS_SUCCESS;
154
}
155
156
/* ---------------------------------------------------------------------------------------------- */
157
/* Hexadecimal */
158
/* ---------------------------------------------------------------------------------------------- */
159
160
#if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN) || defined(ZYAN_WASM) || defined(ZYAN_PPC)
161
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
ZyanStatus ZydisStringAppendHexU64(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
235
ZyanBool force_leading_number, ZyanBool uppercase)
236
{
237
ZYAN_ASSERT(string);
238
ZYAN_ASSERT(!string->vector.allocator);
239
240
const ZyanUSize len = string->vector.size;
241
const ZyanUSize remaining = string->vector.capacity - string->vector.size;
242
243
if (remaining < (ZyanUSize)padding_length)
244
{
245
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
246
}
247
248
if (!value)
249
{
250
const ZyanU8 n = (padding_length ? padding_length : 1);
251
252
if (remaining < (ZyanUSize)n)
253
{
254
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
255
}
256
257
ZYAN_MEMSET((char*)string->vector.data + len - 1, '0', n);
258
string->vector.size = len + n;
259
ZYDIS_STRING_NULLTERMINATE(string);
260
261
return ZYAN_STATUS_SUCCESS;
262
}
263
264
ZyanU8 n = 0;
265
char* buffer = ZYAN_NULL;
266
for (ZyanI8 i = ((value & 0xFFFFFFFF00000000) ?
267
ZYDIS_MAXCHARS_HEX_64 : ZYDIS_MAXCHARS_HEX_32) - 1; i >= 0; --i)
268
{
269
const ZyanU8 v = (value >> i * 4) & 0x0F;
270
if (!n)
271
{
272
if (!v)
273
{
274
continue;
275
}
276
const ZyanU8 zero = force_leading_number && (v > 9) && (padding_length <= i) ? 1 : 0;
277
if (remaining <= (ZyanUSize)i + zero)
278
{
279
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
280
}
281
buffer = (char*)string->vector.data + len - 1;
282
if (zero)
283
{
284
buffer[n++] = '0';
285
}
286
if (padding_length > i)
287
{
288
n = padding_length - i - 1;
289
ZYAN_MEMSET(buffer, '0', n);
290
}
291
}
292
ZYAN_ASSERT(buffer);
293
if (uppercase)
294
{
295
buffer[n++] = "0123456789ABCDEF"[v];
296
} else
297
{
298
buffer[n++] = "0123456789abcdef"[v];
299
}
300
}
301
string->vector.size = len + n;
302
ZYDIS_STRING_NULLTERMINATE(string);
303
304
return ZYAN_STATUS_SUCCESS;
305
}
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
{
320
if (prefix)
321
{
322
ZYAN_CHECK(ZydisStringAppend(string, prefix));
323
}
324
325
#if defined(ZYAN_X64) || defined(ZYAN_AARCH64) || defined(ZYAN_PPC64) || defined(ZYAN_RISCV64)
326
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
if (suffix)
336
{
337
return ZydisStringAppend(string, suffix);
338
}
339
return ZYAN_STATUS_SUCCESS;
340
}
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
{
346
if (prefix)
347
{
348
ZYAN_CHECK(ZydisStringAppend(string, prefix));
349
}
350
351
#if defined(ZYAN_X64) || defined(ZYAN_AARCH64) || defined(ZYAN_PPC64) || defined(ZYAN_RISCV64)
352
ZYAN_CHECK(ZydisStringAppendHexU64(string, value, padding_length, force_leading_number,
353
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
if (suffix)
368
{
369
return ZydisStringAppend(string, suffix);
370
}
371
return ZYAN_STATUS_SUCCESS;
372
}
373
374
/* ---------------------------------------------------------------------------------------------- */
375
376
/* ============================================================================================== */
377
378