Coverage Report

Created: 2026-03-12 06:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/zydis/src/String.c
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
/* ============================================================================================== */