1 /***************************************************************************************************
2
3 Zyan Core Library (Zycore-C)
4
5 Original Author : Florian Bernd
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/Zycore/Format.h"
28 #include "zydis/Zycore/LibC.h"
29
30 /* ============================================================================================== */
31 /* Constants */
32 /* ============================================================================================== */
33
34 /* ---------------------------------------------------------------------------------------------- */
35 /* Defines */
36 /* ---------------------------------------------------------------------------------------------- */
37
38 #define ZYCORE_MAXCHARS_DEC_32 10
39 #define ZYCORE_MAXCHARS_DEC_64 20
40 #define ZYCORE_MAXCHARS_HEX_32 8
41 #define ZYCORE_MAXCHARS_HEX_64 16
42
43 /* ---------------------------------------------------------------------------------------------- */
44 /* Lookup Tables */
45 /* ---------------------------------------------------------------------------------------------- */
46
47 static const char* const DECIMAL_LOOKUP =
48 "00010203040506070809"
49 "10111213141516171819"
50 "20212223242526272829"
51 "30313233343536373839"
52 "40414243444546474849"
53 "50515253545556575859"
54 "60616263646566676869"
55 "70717273747576777879"
56 "80818283848586878889"
57 "90919293949596979899";
58
59 /* ---------------------------------------------------------------------------------------------- */
60 /* Static strings */
61 /* ---------------------------------------------------------------------------------------------- */
62
63 static const ZyanStringView STR_ADD = ZYAN_DEFINE_STRING_VIEW("+");
64 static const ZyanStringView STR_SUB = ZYAN_DEFINE_STRING_VIEW("-");
65
66 /* ---------------------------------------------------------------------------------------------- */
67
68 /* ============================================================================================== */
69 /* Internal macros */
70 /* ============================================================================================== */
71
72 /**
73 * @brief Writes a terminating '\0' character at the end of the string data.
74 */
75 #define ZYCORE_STRING_NULLTERMINATE(string) \
76 *(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) = '\0';
77
78 /* ============================================================================================== */
79 /* Internal functions */
80 /* ============================================================================================== */
81
82 /* ---------------------------------------------------------------------------------------------- */
83 /* Decimal */
84 /* ---------------------------------------------------------------------------------------------- */
85
86 #if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN)
ZyanStringAppendDecU32(ZyanString * string,ZyanU32 value,ZyanU8 padding_length)87 ZyanStatus ZyanStringAppendDecU32(ZyanString* string, ZyanU32 value, ZyanU8 padding_length)
88 {
89 if (!string)
90 {
91 return ZYAN_STATUS_INVALID_ARGUMENT;
92 }
93
94 char buffer[ZYCORE_MAXCHARS_DEC_32];
95 char *buffer_end = &buffer[ZYCORE_MAXCHARS_DEC_32];
96 char *buffer_write_pointer = buffer_end;
97 while (value >= 100)
98 {
99 const ZyanU32 value_old = value;
100 buffer_write_pointer -= 2;
101 value /= 100;
102 ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[(value_old - (value * 100)) * 2], 2);
103 }
104 buffer_write_pointer -= 2;
105 ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[value * 2], 2);
106
107 const ZyanUSize offset_odd = (ZyanUSize)(value < 10);
108 const ZyanUSize length_number = buffer_end - buffer_write_pointer - offset_odd;
109 const ZyanUSize length_total = ZYAN_MAX(length_number, padding_length);
110 const ZyanUSize length_target = string->vector.size;
111
112 if (string->vector.size + length_total > string->vector.capacity)
113 {
114 ZYAN_CHECK(ZyanStringResize(string, string->vector.size + length_total - 1));
115 }
116
117 ZyanUSize offset_write = 0;
118 if (padding_length > length_number)
119 {
120 offset_write = padding_length - length_number;
121 ZYAN_MEMSET((char*)string->vector.data + length_target - 1, '0', offset_write);
122 }
123
124 ZYAN_MEMCPY((char*)string->vector.data + length_target + offset_write - 1,
125 buffer_write_pointer + offset_odd, length_number);
126 string->vector.size = length_target + length_total;
127 ZYCORE_STRING_NULLTERMINATE(string);
128
129 return ZYAN_STATUS_SUCCESS;
130 }
131 #endif
132
ZyanStringAppendDecU64(ZyanString * string,ZyanU64 value,ZyanU8 padding_length)133 ZyanStatus ZyanStringAppendDecU64(ZyanString* string, ZyanU64 value, ZyanU8 padding_length)
134 {
135 if (!string)
136 {
137 return ZYAN_STATUS_INVALID_ARGUMENT;
138 }
139
140 char buffer[ZYCORE_MAXCHARS_DEC_64];
141 char *buffer_end = &buffer[ZYCORE_MAXCHARS_DEC_64];
142 char *buffer_write_pointer = buffer_end;
143 while (value >= 100)
144 {
145 const ZyanU64 value_old = value;
146 buffer_write_pointer -= 2;
147 value /= 100;
148 ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[(value_old - (value * 100)) * 2], 2);
149 }
150 buffer_write_pointer -= 2;
151 ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[value * 2], 2);
152
153 const ZyanUSize offset_odd = (ZyanUSize)(value < 10);
154 const ZyanUSize length_number = buffer_end - buffer_write_pointer - offset_odd;
155 const ZyanUSize length_total = ZYAN_MAX(length_number, padding_length);
156 const ZyanUSize length_target = string->vector.size;
157
158 if (string->vector.size + length_total > string->vector.capacity)
159 {
160 ZYAN_CHECK(ZyanStringResize(string, string->vector.size + length_total - 1));
161 }
162
163 ZyanUSize offset_write = 0;
164 if (padding_length > length_number)
165 {
166 offset_write = padding_length - length_number;
167 ZYAN_MEMSET((char*)string->vector.data + length_target - 1, '0', offset_write);
168 }
169
170 ZYAN_MEMCPY((char*)string->vector.data + length_target + offset_write - 1,
171 buffer_write_pointer + offset_odd, length_number);
172 string->vector.size = length_target + length_total;
173 ZYCORE_STRING_NULLTERMINATE(string);
174
175 return ZYAN_STATUS_SUCCESS;
176 }
177
178 /* ---------------------------------------------------------------------------------------------- */
179 /* Hexadecimal */
180 /* ---------------------------------------------------------------------------------------------- */
181
182 #if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN)
ZyanStringAppendHexU32(ZyanString * string,ZyanU32 value,ZyanU8 padding_length,ZyanBool uppercase)183 ZyanStatus ZyanStringAppendHexU32(ZyanString* string, ZyanU32 value, ZyanU8 padding_length,
184 ZyanBool uppercase)
185 {
186 if (!string)
187 {
188 return ZYAN_STATUS_INVALID_ARGUMENT;
189 }
190
191 const ZyanUSize len = string->vector.size;
192 ZyanUSize remaining = string->vector.capacity - string->vector.size;
193
194 if (remaining < (ZyanUSize)padding_length)
195 {
196 ZYAN_CHECK(ZyanStringResize(string, len + padding_length - 1));
197 remaining = padding_length;
198 }
199
200 if (!value)
201 {
202 const ZyanU8 n = (padding_length ? padding_length : 1);
203
204 if (remaining < (ZyanUSize)n)
205 {
206 ZYAN_CHECK(ZyanStringResize(string, string->vector.size + n - 1));
207 }
208
209 ZYAN_MEMSET((char*)string->vector.data + len - 1, '0', n);
210 string->vector.size = len + n;
211 ZYCORE_STRING_NULLTERMINATE(string);
212
213 return ZYAN_STATUS_SUCCESS;
214 }
215
216 ZyanU8 n = 0;
217 char* buffer = ZYAN_NULL;
218 for (ZyanI8 i = ZYCORE_MAXCHARS_HEX_32 - 1; i >= 0; --i)
219 {
220 const ZyanU8 v = (value >> i * 4) & 0x0F;
221 if (!n)
222 {
223 if (!v)
224 {
225 continue;
226 }
227 if (remaining <= (ZyanU8)i)
228 {
229 ZYAN_CHECK(ZyanStringResize(string, string->vector.size + i));
230 }
231 buffer = (char*)string->vector.data + len - 1;
232 if (padding_length > i)
233 {
234 n = padding_length - i - 1;
235 ZYAN_MEMSET(buffer, '0', n);
236 }
237 }
238 ZYAN_ASSERT(buffer);
239 if (uppercase)
240 {
241 buffer[n++] = "0123456789ABCDEF"[v];
242 } else
243 {
244 buffer[n++] = "0123456789abcdef"[v];
245 }
246 }
247 string->vector.size = len + n;
248 ZYCORE_STRING_NULLTERMINATE(string);
249
250 return ZYAN_STATUS_SUCCESS;
251 }
252 #endif
253
ZyanStringAppendHexU64(ZyanString * string,ZyanU64 value,ZyanU8 padding_length,ZyanBool uppercase)254 ZyanStatus ZyanStringAppendHexU64(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
255 ZyanBool uppercase)
256 {
257 if (!string)
258 {
259 return ZYAN_STATUS_INVALID_ARGUMENT;
260 }
261
262 const ZyanUSize len = string->vector.size;
263 ZyanUSize remaining = string->vector.capacity - string->vector.size;
264
265 if (remaining < (ZyanUSize)padding_length)
266 {
267 ZYAN_CHECK(ZyanStringResize(string, len + padding_length - 1));
268 remaining = padding_length;
269 }
270
271 if (!value)
272 {
273 const ZyanU8 n = (padding_length ? padding_length : 1);
274
275 if (remaining < (ZyanUSize)n)
276 {
277 ZYAN_CHECK(ZyanStringResize(string, string->vector.size + n - 1));
278 }
279
280 ZYAN_MEMSET((char*)string->vector.data + len - 1, '0', n);
281 string->vector.size = len + n;
282 ZYCORE_STRING_NULLTERMINATE(string);
283
284 return ZYAN_STATUS_SUCCESS;
285 }
286
287 ZyanU8 n = 0;
288 char* buffer = ZYAN_NULL;
289 for (ZyanI8 i = ((value & 0xFFFFFFFF00000000) ?
290 ZYCORE_MAXCHARS_HEX_64 : ZYCORE_MAXCHARS_HEX_32) - 1; i >= 0; --i)
291 {
292 const ZyanU8 v = (value >> i * 4) & 0x0F;
293 if (!n)
294 {
295 if (!v)
296 {
297 continue;
298 }
299 if (remaining <= (ZyanU8)i)
300 {
301 ZYAN_CHECK(ZyanStringResize(string, string->vector.size + i));
302 }
303 buffer = (char*)string->vector.data + len - 1;
304 if (padding_length > i)
305 {
306 n = padding_length - i - 1;
307 ZYAN_MEMSET(buffer, '0', n);
308 }
309 }
310 ZYAN_ASSERT(buffer);
311 if (uppercase)
312 {
313 buffer[n++] = "0123456789ABCDEF"[v];
314 } else
315 {
316 buffer[n++] = "0123456789abcdef"[v];
317 }
318 }
319 string->vector.size = len + n;
320 ZYCORE_STRING_NULLTERMINATE(string);
321
322 return ZYAN_STATUS_SUCCESS;
323 }
324
325 /* ---------------------------------------------------------------------------------------------- */
326
327 /* ============================================================================================== */
328 /* Exported functions */
329 /* ============================================================================================== */
330
331 /* ---------------------------------------------------------------------------------------------- */
332 /* Insertion */
333 /* ---------------------------------------------------------------------------------------------- */
334
335 //ZyanStatus ZyanStringInsertFormat(ZyanString* string, ZyanUSize index, const char* format, ...)
336 //{
337 //
338 //}
339 //
340 ///* ---------------------------------------------------------------------------------------------- */
341 //
342 //ZyanStatus ZyanStringInsertDecU(ZyanString* string, ZyanUSize index, ZyanU64 value,
343 // ZyanUSize padding_length)
344 //{
345 //
346 //}
347 //
348 //ZyanStatus ZyanStringInsertDecS(ZyanString* string, ZyanUSize index, ZyanI64 value,
349 // ZyanUSize padding_length, ZyanBool force_sign, const ZyanString* prefix)
350 //{
351 //
352 //}
353 //
354 //ZyanStatus ZyanStringInsertHexU(ZyanString* string, ZyanUSize index, ZyanU64 value,
355 // ZyanUSize padding_length, ZyanBool uppercase)
356 //{
357 //
358 //}
359 //
360 //ZyanStatus ZyanStringInsertHexS(ZyanString* string, ZyanUSize index, ZyanI64 value,
361 // ZyanUSize padding_length, ZyanBool uppercase, ZyanBool force_sign, const ZyanString* prefix)
362 //{
363 //
364 //}
365
366 /* ---------------------------------------------------------------------------------------------- */
367 /* Appending */
368 /* ---------------------------------------------------------------------------------------------- */
369
370 #ifndef ZYAN_NO_LIBC
371
ZyanStringAppendFormat(ZyanString * string,const char * format,...)372 ZyanStatus ZyanStringAppendFormat(ZyanString* string, const char* format, ...)
373 {
374 if (!string || !format)
375 {
376 return ZYAN_STATUS_INVALID_ARGUMENT;
377 }
378
379 ZyanVAList arglist;
380 ZYAN_VA_START(arglist, format);
381
382 const ZyanUSize len = string->vector.size;
383
384 ZyanI32 w = ZYAN_VSNPRINTF((char*)string->vector.data + len - 1,
385 string->vector.capacity - len + 1, format, arglist);
386 if (w < 0)
387 {
388 ZYAN_VA_END(arglist);
389 return ZYAN_STATUS_FAILED;
390 }
391 if (w <= (ZyanI32)(string->vector.capacity - len))
392 {
393 string->vector.size = len + w;
394
395 ZYAN_VA_END(arglist);
396 return ZYAN_STATUS_SUCCESS;
397 }
398
399 // The remaining capacity was not sufficent to fit the formatted string. Trying to resize ..
400 const ZyanStatus status = ZyanStringResize(string, string->vector.size + w - 1);
401 if (!ZYAN_SUCCESS(status))
402 {
403 ZYAN_VA_END(arglist);
404 return status;
405 }
406
407 w = ZYAN_VSNPRINTF((char*)string->vector.data + len - 1,
408 string->vector.capacity - string->vector.size + 1, format, arglist);
409 if (w < 0)
410 {
411 ZYAN_VA_END(arglist);
412 return ZYAN_STATUS_FAILED;
413 }
414 ZYAN_ASSERT(w <= (ZyanI32)(string->vector.capacity - string->vector.size));
415
416 ZYAN_VA_END(arglist);
417 return ZYAN_STATUS_SUCCESS;
418 }
419
420 #endif // ZYAN_NO_LIBC
421
422 /* ---------------------------------------------------------------------------------------------- */
423
ZyanStringAppendDecU(ZyanString * string,ZyanU64 value,ZyanU8 padding_length)424 ZyanStatus ZyanStringAppendDecU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length)
425 {
426 #if defined(ZYAN_X64) || defined(ZYAN_AARCH64)
427 return ZyanStringAppendDecU64(string, value, padding_length);
428 #else
429 // Working with 64-bit values is slow on non 64-bit systems
430 if (value & 0xFFFFFFFF00000000)
431 {
432 return ZyanStringAppendDecU64(string, value, padding_length);
433 }
434 return ZyanStringAppendDecU32(string, (ZyanU32)value, padding_length);
435 #endif
436 }
437
ZyanStringAppendDecS(ZyanString * string,ZyanI64 value,ZyanU8 padding_length,ZyanBool force_sign,const ZyanStringView * prefix)438 ZyanStatus ZyanStringAppendDecS(ZyanString* string, ZyanI64 value, ZyanU8 padding_length,
439 ZyanBool force_sign, const ZyanStringView* prefix)
440 {
441 if (value < 0)
442 {
443 ZYAN_CHECK(ZyanStringAppend(string, &STR_SUB));
444 if (prefix)
445 {
446 ZYAN_CHECK(ZyanStringAppend(string, prefix));
447 }
448 return ZyanStringAppendDecU(string, -value, padding_length);
449 }
450
451 if (force_sign)
452 {
453 ZYAN_ASSERT(value >= 0);
454 ZYAN_CHECK(ZyanStringAppend(string, &STR_ADD));
455 }
456
457 if (prefix)
458 {
459 ZYAN_CHECK(ZyanStringAppend(string, prefix));
460 }
461 return ZyanStringAppendDecU(string, value, padding_length);
462 }
463
ZyanStringAppendHexU(ZyanString * string,ZyanU64 value,ZyanU8 padding_length,ZyanBool uppercase)464 ZyanStatus ZyanStringAppendHexU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
465 ZyanBool uppercase)
466 {
467 #if defined(ZYAN_X64) || defined(ZYAN_AARCH64)
468 return ZyanStringAppendHexU64(string, value, padding_length, uppercase);
469 #else
470 // Working with 64-bit values is slow on non 64-bit systems
471 if (value & 0xFFFFFFFF00000000)
472 {
473 return ZyanStringAppendHexU64(string, value, padding_length, uppercase);
474 }
475 return ZyanStringAppendHexU32(string, (ZyanU32)value, padding_length, uppercase);
476 #endif
477 }
478
ZyanStringAppendHexS(ZyanString * string,ZyanI64 value,ZyanU8 padding_length,ZyanBool uppercase,ZyanBool force_sign,const ZyanStringView * prefix)479 ZyanStatus ZyanStringAppendHexS(ZyanString* string, ZyanI64 value, ZyanU8 padding_length,
480 ZyanBool uppercase, ZyanBool force_sign, const ZyanStringView* prefix)
481 {
482 if (value < 0)
483 {
484 ZYAN_CHECK(ZyanStringAppend(string, &STR_SUB));
485 if (prefix)
486 {
487 ZYAN_CHECK(ZyanStringAppend(string, prefix));
488 }
489 return ZyanStringAppendHexU(string, -value, padding_length, uppercase);
490 }
491
492 if (force_sign)
493 {
494 ZYAN_ASSERT(value >= 0);
495 ZYAN_CHECK(ZyanStringAppend(string, &STR_ADD));
496 }
497
498 if (prefix)
499 {
500 ZYAN_CHECK(ZyanStringAppend(string, prefix));
501 }
502 return ZyanStringAppendHexU(string, value, padding_length, uppercase);
503 }
504
505 /* ---------------------------------------------------------------------------------------------- */
506
507 /* ============================================================================================== */
508