1 /***************************************************************************************************
3 Zyan Disassembler Library (Zydis)
5 Original Author : Florian Bernd, Joel Hoener
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:
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
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
25 ***************************************************************************************************/
27 #include <Zydis/Internal/String.h>
29 /* ============================================================================================== */
31 /* ============================================================================================== */
33 /* ---------------------------------------------------------------------------------------------- */
35 /* ---------------------------------------------------------------------------------------------- */
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
42 /* ---------------------------------------------------------------------------------------------- */
44 /* ---------------------------------------------------------------------------------------------- */
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";
58 /* ---------------------------------------------------------------------------------------------- */
60 /* ============================================================================================== */
61 /* Internal Functions */
62 /* ============================================================================================== */
64 /* ---------------------------------------------------------------------------------------------- */
66 /* ---------------------------------------------------------------------------------------------- */
68 #if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN) || defined(ZYAN_WASM) || defined(ZYAN_PPC)
69 static ZyanStatus
ZydisStringAppendDecU32(ZyanString
* string
, ZyanU32 value
, ZyanU8 padding_length
)
72 ZYAN_ASSERT(!string
->vector
.allocator
);
74 char buffer
[ZYDIS_MAXCHARS_DEC_32
];
75 char *buffer_end
= &buffer
[ZYDIS_MAXCHARS_DEC_32
];
76 char *buffer_write_pointer
= buffer_end
;
79 const ZyanU32 value_old
= value
;
80 buffer_write_pointer
-= 2;
82 ZYAN_MEMCPY(buffer_write_pointer
, &DECIMAL_LOOKUP
[(value_old
- (value
* 100)) * 2], 2);
84 buffer_write_pointer
-= 2;
85 ZYAN_MEMCPY(buffer_write_pointer
, &DECIMAL_LOOKUP
[value
* 2], 2);
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
;
92 if (string
->vector
.size
+ length_total
> string
->vector
.capacity
)
94 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE
;
97 ZyanUSize offset_write
= 0;
98 if (padding_length
> length_number
)
100 offset_write
= padding_length
- length_number
;
101 ZYAN_MEMSET((char*)string
->vector
.data
+ length_target
- 1, '0', offset_write
);
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
);
109 return ZYAN_STATUS_SUCCESS
;
113 static ZyanStatus
ZydisStringAppendDecU64(ZyanString
* string
, ZyanU64 value
, ZyanU8 padding_length
)
116 ZYAN_ASSERT(!string
->vector
.allocator
);
118 char buffer
[ZYDIS_MAXCHARS_DEC_64
];
119 char *buffer_end
= &buffer
[ZYDIS_MAXCHARS_DEC_64
];
120 char *buffer_write_pointer
= buffer_end
;
123 const ZyanU64 value_old
= value
;
124 buffer_write_pointer
-= 2;
125 ZYAN_DIV64(value
, 100);
126 ZYAN_MEMCPY(buffer_write_pointer
, &DECIMAL_LOOKUP
[(value_old
- (value
* 100)) * 2], 2);
128 buffer_write_pointer
-= 2;
129 ZYAN_MEMCPY(buffer_write_pointer
, &DECIMAL_LOOKUP
[value
* 2], 2);
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
;
136 if (string
->vector
.size
+ length_total
> string
->vector
.capacity
)
138 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE
;
141 ZyanUSize offset_write
= 0;
142 if (padding_length
> length_number
)
144 offset_write
= padding_length
- length_number
;
145 ZYAN_MEMSET((char*)string
->vector
.data
+ length_target
- 1, '0', offset_write
);
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
);
153 return ZYAN_STATUS_SUCCESS
;
156 /* ---------------------------------------------------------------------------------------------- */
158 /* ---------------------------------------------------------------------------------------------- */
160 #if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN) || defined(ZYAN_WASM) || defined(ZYAN_PPC)
161 static ZyanStatus
ZydisStringAppendHexU32(ZyanString
* string
, ZyanU32 value
, ZyanU8 padding_length
,
162 ZyanBool force_leading_number
, ZyanBool uppercase
)
165 ZYAN_ASSERT(!string
->vector
.allocator
);
167 const ZyanUSize len
= string
->vector
.size
;
168 const ZyanUSize remaining
= string
->vector
.capacity
- string
->vector
.size
;
170 if (remaining
< (ZyanUSize
)padding_length
)
172 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE
;
177 const ZyanU8 n
= (padding_length
? padding_length
: 1);
179 if (remaining
< (ZyanUSize
)n
)
181 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE
;
184 ZYAN_MEMSET((char*)string
->vector
.data
+ len
- 1, '0', n
);
185 string
->vector
.size
= len
+ n
;
186 ZYDIS_STRING_NULLTERMINATE(string
);
188 return ZYAN_STATUS_SUCCESS
;
192 char* buffer
= ZYAN_NULL
;
193 for (ZyanI8 i
= ZYDIS_MAXCHARS_HEX_32
- 1; i
>= 0; --i
)
195 const ZyanU8 v
= (value
>> i
* 4) & 0x0F;
202 const ZyanU8 zero
= force_leading_number
&& (v
> 9) && (padding_length
<= i
) ? 1 : 0;
203 if (remaining
<= (ZyanUSize
)i
+ zero
)
205 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE
;
207 buffer
= (char*)string
->vector
.data
+ len
- 1;
212 if (padding_length
> i
)
214 n
= padding_length
- i
- 1;
215 ZYAN_MEMSET(buffer
, '0', n
);
221 buffer
[n
++] = "0123456789ABCDEF"[v
];
224 buffer
[n
++] = "0123456789abcdef"[v
];
227 string
->vector
.size
= len
+ n
;
228 ZYDIS_STRING_NULLTERMINATE(string
);
230 return ZYAN_STATUS_SUCCESS
;
234 static ZyanStatus
ZydisStringAppendHexU64(ZyanString
* string
, ZyanU64 value
, ZyanU8 padding_length
,
235 ZyanBool force_leading_number
, ZyanBool uppercase
)
238 ZYAN_ASSERT(!string
->vector
.allocator
);
240 const ZyanUSize len
= string
->vector
.size
;
241 const ZyanUSize remaining
= string
->vector
.capacity
- string
->vector
.size
;
243 if (remaining
< (ZyanUSize
)padding_length
)
245 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE
;
250 const ZyanU8 n
= (padding_length
? padding_length
: 1);
252 if (remaining
< (ZyanUSize
)n
)
254 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE
;
257 ZYAN_MEMSET((char*)string
->vector
.data
+ len
- 1, '0', n
);
258 string
->vector
.size
= len
+ n
;
259 ZYDIS_STRING_NULLTERMINATE(string
);
261 return ZYAN_STATUS_SUCCESS
;
265 char* buffer
= ZYAN_NULL
;
266 for (ZyanI8 i
= ((value
& 0xFFFFFFFF00000000) ?
267 ZYDIS_MAXCHARS_HEX_64
: ZYDIS_MAXCHARS_HEX_32
) - 1; i
>= 0; --i
)
269 const ZyanU8 v
= (value
>> i
* 4) & 0x0F;
276 const ZyanU8 zero
= force_leading_number
&& (v
> 9) && (padding_length
<= i
) ? 1 : 0;
277 if (remaining
<= (ZyanUSize
)i
+ zero
)
279 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE
;
281 buffer
= (char*)string
->vector
.data
+ len
- 1;
286 if (padding_length
> i
)
288 n
= padding_length
- i
- 1;
289 ZYAN_MEMSET(buffer
, '0', n
);
295 buffer
[n
++] = "0123456789ABCDEF"[v
];
298 buffer
[n
++] = "0123456789abcdef"[v
];
301 string
->vector
.size
= len
+ n
;
302 ZYDIS_STRING_NULLTERMINATE(string
);
304 return ZYAN_STATUS_SUCCESS
;
307 /* ---------------------------------------------------------------------------------------------- */
309 /* ============================================================================================== */
310 /* Public Functions */
311 /* ============================================================================================== */
313 /* ---------------------------------------------------------------------------------------------- */
315 /* ---------------------------------------------------------------------------------------------- */
317 ZyanStatus
ZydisStringAppendDecU(ZyanString
* string
, ZyanU64 value
, ZyanU8 padding_length
,
318 const ZyanStringView
* prefix
, const ZyanStringView
* suffix
)
322 ZYAN_CHECK(ZydisStringAppend(string
, prefix
));
325 #if defined(ZYAN_X64) || defined(ZYAN_AARCH64) || defined(ZYAN_PPC64) || defined(ZYAN_RISCV64) || defined(ZYAN_LOONGARCH)
326 ZYAN_CHECK(ZydisStringAppendDecU64(string
, value
, padding_length
));
328 if (value
& 0xFFFFFFFF00000000)
330 ZYAN_CHECK(ZydisStringAppendDecU64(string
, value
, padding_length
));
332 ZYAN_CHECK(ZydisStringAppendDecU32(string
, (ZyanU32
)value
, padding_length
));
337 return ZydisStringAppend(string
, suffix
);
339 return ZYAN_STATUS_SUCCESS
;
342 ZyanStatus
ZydisStringAppendHexU(ZyanString
* string
, ZyanU64 value
, ZyanU8 padding_length
,
343 ZyanBool force_leading_number
, ZyanBool uppercase
, const ZyanStringView
* prefix
,
344 const ZyanStringView
* suffix
)
348 ZYAN_CHECK(ZydisStringAppend(string
, prefix
));
351 #if defined(ZYAN_X64) || defined(ZYAN_AARCH64) || defined(ZYAN_PPC64) || defined(ZYAN_RISCV64) || defined(ZYAN_LOONGARCH)
352 ZYAN_CHECK(ZydisStringAppendHexU64(string
, value
, padding_length
, force_leading_number
,
355 if (value
& 0xFFFFFFFF00000000)
357 ZYAN_CHECK(ZydisStringAppendHexU64(string
, value
, padding_length
, force_leading_number
,
362 ZYAN_CHECK(ZydisStringAppendHexU32(string
, (ZyanU32
)value
, padding_length
,
363 force_leading_number
, uppercase
));
369 return ZydisStringAppend(string
, suffix
);
371 return ZYAN_STATUS_SUCCESS
;
374 /* ---------------------------------------------------------------------------------------------- */
376 /* ============================================================================================== */