mirror of
				https://github.com/RetroDECK/Duckstation.git
				synced 2025-04-10 19:15:14 +00:00 
			
		
		
		
	
		
			
	
	
		
			471 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			471 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /***************************************************************************************************
 | ||
|  | 
 | ||
|  |   Zyan Disassembler Library (Zydis) | ||
|  | 
 | ||
|  |   Original Author : Florian Bernd, Joel Hoener | ||
|  | 
 | ||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||
|  |  * in the Software without restriction, including without limitation the rights | ||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||
|  |  * furnished to do so, subject to the following conditions: | ||
|  |  * | ||
|  |  * The above copyright notice and this permission notice shall be included in all | ||
|  |  * copies or substantial portions of the Software. | ||
|  |  * | ||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
|  |  * SOFTWARE. | ||
|  | 
 | ||
|  | ***************************************************************************************************/ | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * @file | ||
|  |  * Provides some internal, more performant, but unsafe helper functions for the `ZyanString` | ||
|  |  * data-type. | ||
|  |  * | ||
|  |  * Most of these functions are very similar to the ones in `Zycore/String.h`, but inlined and | ||
|  |  * without optional overhead like parameter-validation checks, etc ... | ||
|  |  * | ||
|  |  * The `ZyanString` data-type is able to dynamically allocate memory on the heap, but as `Zydis` is | ||
|  |  * designed to be a non-'malloc'ing library, all functions in this file assume that the instances | ||
|  |  * they are operating on are created with a user-defined static-buffer. | ||
|  |  */ | ||
|  | 
 | ||
|  | #ifndef ZYDIS_INTERNAL_STRING_H
 | ||
|  | #define ZYDIS_INTERNAL_STRING_H
 | ||
|  | 
 | ||
|  | #include <Zycore/LibC.h>
 | ||
|  | #include <Zycore/String.h>
 | ||
|  | #include <Zycore/Types.h>
 | ||
|  | #include <Zycore/Format.h>
 | ||
|  | #include <Zydis/ShortString.h>
 | ||
|  | #include <Zycore/Defines.h>
 | ||
|  | #include <Zycore/Status.h>
 | ||
|  | #include <Zycore/Vector.h>
 | ||
|  | 
 | ||
|  | #ifdef __cplusplus
 | ||
|  | extern "C" { | ||
|  | #endif
 | ||
|  | 
 | ||
|  | /* ============================================================================================== */ | ||
|  | /* Enums and types                                                                                */ | ||
|  | /* ============================================================================================== */ | ||
|  | 
 | ||
|  | /* ---------------------------------------------------------------------------------------------- */ | ||
|  | /* Letter Case                                                                                    */ | ||
|  | /* ---------------------------------------------------------------------------------------------- */ | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Defines the `ZydisLetterCase` enum. | ||
|  |  */ | ||
|  | typedef enum ZydisLetterCase_ | ||
|  | { | ||
|  |     /**
 | ||
|  |      * Uses the given text "as is". | ||
|  |      */ | ||
|  |     ZYDIS_LETTER_CASE_DEFAULT, | ||
|  |     /**
 | ||
|  |      * Converts the given text to lowercase letters. | ||
|  |      */ | ||
|  |     ZYDIS_LETTER_CASE_LOWER, | ||
|  |     /**
 | ||
|  |      * Converts the given text to uppercase letters. | ||
|  |      */ | ||
|  |     ZYDIS_LETTER_CASE_UPPER, | ||
|  | 
 | ||
|  |     /**
 | ||
|  |      * Maximum value of this enum. | ||
|  |      */ | ||
|  |     ZYDIS_LETTER_CASE_MAX_VALUE = ZYDIS_LETTER_CASE_UPPER, | ||
|  |     /**
 | ||
|  |      * The minimum number of bits required to represent all values of this enum. | ||
|  |      */ | ||
|  |     ZYDIS_LETTER_CASE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_LETTER_CASE_MAX_VALUE) | ||
|  | } ZydisLetterCase; | ||
|  | 
 | ||
|  | /* ---------------------------------------------------------------------------------------------- */ | ||
|  | 
 | ||
|  | /* ============================================================================================== */ | ||
|  | /* Macros                                                                                         */ | ||
|  | /* ============================================================================================== */ | ||
|  | 
 | ||
|  | /* ---------------------------------------------------------------------------------------------- */ | ||
|  | /* Internal macros                                                                                */ | ||
|  | /* ---------------------------------------------------------------------------------------------- */ | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Checks for a terminating '\0' character at the end of the string data. | ||
|  |  */ | ||
|  | #define ZYDIS_STRING_ASSERT_NULLTERMINATION(string) \
 | ||
|  |       ZYAN_ASSERT(*(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) == '\0'); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Writes a terminating '\0' character at the end of the string data. | ||
|  |  */ | ||
|  | #define ZYDIS_STRING_NULLTERMINATE(string) \
 | ||
|  |       *(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) = '\0'; | ||
|  | 
 | ||
|  | /* ---------------------------------------------------------------------------------------------- */ | ||
|  | 
 | ||
|  | /* ============================================================================================== */ | ||
|  | /* Internal Functions                                                                             */ | ||
|  | /* ============================================================================================== */ | ||
|  | 
 | ||
|  | /* ---------------------------------------------------------------------------------------------- */ | ||
|  | /* Appending                                                                                      */ | ||
|  | /* ---------------------------------------------------------------------------------------------- */ | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Appends the content of the source string to the end of the destination string. | ||
|  |  * | ||
|  |  * @param   destination The destination string. | ||
|  |  * @param   source      The source string. | ||
|  |  * | ||
|  |  * @return  A zyan status code. | ||
|  |  */ | ||
|  | ZYAN_INLINE ZyanStatus ZydisStringAppend(ZyanString* destination, const ZyanStringView* source) | ||
|  | { | ||
|  |     ZYAN_ASSERT(destination && source); | ||
|  |     ZYAN_ASSERT(!destination->vector.allocator); | ||
|  |     ZYAN_ASSERT(destination->vector.size && source->string.vector.size); | ||
|  | 
 | ||
|  |     if (destination->vector.size + source->string.vector.size - 1 > destination->vector.capacity) | ||
|  |     { | ||
|  |         return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; | ||
|  |     } | ||
|  | 
 | ||
|  |     ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1, | ||
|  |         source->string.vector.data, source->string.vector.size - 1); | ||
|  | 
 | ||
|  |     destination->vector.size += source->string.vector.size - 1; | ||
|  |     ZYDIS_STRING_NULLTERMINATE(destination); | ||
|  | 
 | ||
|  |     return ZYAN_STATUS_SUCCESS; | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Appends the content of the source string to the end of the destination | ||
|  |  * string, converting the characters to the specified letter-case. | ||
|  |  * | ||
|  |  * @param   destination The destination string. | ||
|  |  * @param   source      The source string. | ||
|  |  * @param   letter_case The desired letter-case. | ||
|  |  * | ||
|  |  * @return  A zyan status code. | ||
|  |  */ | ||
|  | ZYAN_INLINE ZyanStatus ZydisStringAppendCase(ZyanString* destination, const ZyanStringView* source, | ||
|  |     ZydisLetterCase letter_case) | ||
|  | { | ||
|  |     ZYAN_ASSERT(destination && source); | ||
|  |     ZYAN_ASSERT(!destination->vector.allocator); | ||
|  |     ZYAN_ASSERT(destination->vector.size && source->string.vector.size); | ||
|  | 
 | ||
|  |     if (destination->vector.size + source->string.vector.size - 1 > destination->vector.capacity) | ||
|  |     { | ||
|  |         return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; | ||
|  |     } | ||
|  | 
 | ||
|  |     ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1, | ||
|  |         source->string.vector.data, source->string.vector.size - 1); | ||
|  | 
 | ||
|  |     switch (letter_case) | ||
|  |     { | ||
|  |     case ZYDIS_LETTER_CASE_DEFAULT: | ||
|  |         break; | ||
|  |     case ZYDIS_LETTER_CASE_LOWER: | ||
|  |     { | ||
|  |         const ZyanUSize index = destination->vector.size - 1; | ||
|  |         const ZyanUSize count = source->string.vector.size - 1; | ||
|  |         char* s = (char*)destination->vector.data + index; | ||
|  |         for (ZyanUSize i = index; i < index + count; ++i) | ||
|  |         { | ||
|  |             const char c = *s; | ||
|  |             if ((c >= 'A') && (c <= 'Z')) | ||
|  |             { | ||
|  |                 *s = c | 32; | ||
|  |             } | ||
|  |             ++s; | ||
|  |         } | ||
|  |         break; | ||
|  |     } | ||
|  |     case ZYDIS_LETTER_CASE_UPPER: | ||
|  |     { | ||
|  |         const ZyanUSize index = destination->vector.size - 1; | ||
|  |         const ZyanUSize count = source->string.vector.size - 1; | ||
|  |         char* s = (char*)destination->vector.data + index; | ||
|  |         for (ZyanUSize i = index; i < index + count; ++i) | ||
|  |         { | ||
|  |             const char c = *s; | ||
|  |             if ((c >= 'a') && (c <= 'z')) | ||
|  |             { | ||
|  |                 *s = c & ~32; | ||
|  |             } | ||
|  |             ++s; | ||
|  |         } | ||
|  |         break; | ||
|  |     } | ||
|  |     default: | ||
|  |         ZYAN_UNREACHABLE; | ||
|  |     } | ||
|  | 
 | ||
|  |     destination->vector.size += source->string.vector.size - 1; | ||
|  |     ZYDIS_STRING_NULLTERMINATE(destination); | ||
|  | 
 | ||
|  |     return ZYAN_STATUS_SUCCESS; | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Appends the content of the source short-string to the end of the destination string. | ||
|  |  * | ||
|  |  * @param   destination The destination string. | ||
|  |  * @param   source      The source string. | ||
|  |  * | ||
|  |  * @return  A zyan status code. | ||
|  |  */ | ||
|  | ZYAN_INLINE ZyanStatus ZydisStringAppendShort(ZyanString* destination, | ||
|  |     const ZydisShortString* source) | ||
|  | { | ||
|  |     ZYAN_ASSERT(destination && source); | ||
|  |     ZYAN_ASSERT(!destination->vector.allocator); | ||
|  |     ZYAN_ASSERT(destination->vector.size && source->size); | ||
|  | 
 | ||
|  |     if (destination->vector.size + source->size > destination->vector.capacity) | ||
|  |     { | ||
|  |         return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; | ||
|  |     } | ||
|  | 
 | ||
|  |     ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1, source->data, | ||
|  |         (ZyanUSize)source->size + 1); | ||
|  | 
 | ||
|  |     destination->vector.size += source->size; | ||
|  |     ZYDIS_STRING_ASSERT_NULLTERMINATION(destination); | ||
|  | 
 | ||
|  |     return ZYAN_STATUS_SUCCESS; | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Appends the content of the source short-string to the end of the destination string, | ||
|  |  * converting the characters to the specified letter-case. | ||
|  |  * | ||
|  |  * @param   destination The destination string. | ||
|  |  * @param   source      The source string. | ||
|  |  * @param   letter_case The desired letter-case. | ||
|  |  * | ||
|  |  * @return  A zyan status code. | ||
|  |  */ | ||
|  | ZYAN_INLINE ZyanStatus ZydisStringAppendShortCase(ZyanString* destination, | ||
|  |     const ZydisShortString* source, ZydisLetterCase letter_case) | ||
|  | { | ||
|  |     ZYAN_ASSERT(destination && source); | ||
|  |     ZYAN_ASSERT(!destination->vector.allocator); | ||
|  |     ZYAN_ASSERT(destination->vector.size && source->size); | ||
|  | 
 | ||
|  |     if (destination->vector.size + source->size > destination->vector.capacity) | ||
|  |     { | ||
|  |         return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; | ||
|  |     } | ||
|  | 
 | ||
|  |     ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1, source->data, | ||
|  |         (ZyanUSize)source->size + 1); | ||
|  | 
 | ||
|  |     switch (letter_case) | ||
|  |     { | ||
|  |     case ZYDIS_LETTER_CASE_DEFAULT: | ||
|  |         break; | ||
|  |     case ZYDIS_LETTER_CASE_LOWER: | ||
|  |     { | ||
|  |         const ZyanUSize index = destination->vector.size - 1; | ||
|  |         const ZyanUSize count = source->size; | ||
|  |         char* s = (char*)destination->vector.data + index; | ||
|  |         for (ZyanUSize i = index; i < index + count; ++i) | ||
|  |         { | ||
|  |             const char c = *s; | ||
|  |             if ((c >= 'A') && (c <= 'Z')) | ||
|  |             { | ||
|  |                 *s = c | 32; | ||
|  |             } | ||
|  |             ++s; | ||
|  |         } | ||
|  |         break; | ||
|  |     } | ||
|  |     case ZYDIS_LETTER_CASE_UPPER: | ||
|  |     { | ||
|  |         const ZyanUSize index = destination->vector.size - 1; | ||
|  |         const ZyanUSize count = source->size; | ||
|  |         char* s = (char*)destination->vector.data + index; | ||
|  |         for (ZyanUSize i = index; i < index + count; ++i) | ||
|  |         { | ||
|  |             const char c = *s; | ||
|  |             if ((c >= 'a') && (c <= 'z')) | ||
|  |             { | ||
|  |                 *s = c & ~32; | ||
|  |             } | ||
|  |             ++s; | ||
|  |         } | ||
|  |         break; | ||
|  |     } | ||
|  |     default: | ||
|  |         ZYAN_UNREACHABLE; | ||
|  |     } | ||
|  | 
 | ||
|  |     destination->vector.size += source->size; | ||
|  |     ZYDIS_STRING_ASSERT_NULLTERMINATION(destination); | ||
|  | 
 | ||
|  |     return ZYAN_STATUS_SUCCESS; | ||
|  | } | ||
|  | 
 | ||
|  | /* ---------------------------------------------------------------------------------------------- */ | ||
|  | /* Formatting                                                                                     */ | ||
|  | /* ---------------------------------------------------------------------------------------------- */ | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Formats the given unsigned ordinal `value` to its decimal text-representation and | ||
|  |  * appends it to the `string`. | ||
|  |  * | ||
|  |  * @param   string          A pointer to the `ZyanString` instance. | ||
|  |  * @param   value           The value to append. | ||
|  |  * @param   padding_length  Padds the converted value with leading zeros, if the number of chars is | ||
|  |  *                          less than the `padding_length`. | ||
|  |  * @param   prefix          The string to use as prefix or `ZYAN_NULL`, if not needed. | ||
|  |  * @param   suffix          The string to use as suffix or `ZYAN_NULL`, if not needed. | ||
|  |  * | ||
|  |  * @return  A zyan status code. | ||
|  |  * | ||
|  |  * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified | ||
|  |  * `ZyanString` instance. | ||
|  |  */ | ||
|  | ZyanStatus ZydisStringAppendDecU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length, | ||
|  |     const ZyanStringView* prefix, const ZyanStringView* suffix); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Formats the given signed ordinal `value` to its decimal text-representation and | ||
|  |  * appends it to the `string`. | ||
|  |  * | ||
|  |  * @param   string          A pointer to the `ZyanString` instance. | ||
|  |  * @param   value           The value to append. | ||
|  |  * @param   padding_length  Padds the converted value with leading zeros, if the number of chars is | ||
|  |  *                          less than the `padding_length`. | ||
|  |  * @param   force_sign      Enable this option to print the `+` sign for positive numbers. | ||
|  |  * @param   prefix          The string to use as prefix or `ZYAN_NULL`, if not needed. | ||
|  |  * @param   suffix          The string to use as suffix or `ZYAN_NULL`, if not needed. | ||
|  |  * | ||
|  |  * @return  A zyan status code. | ||
|  |  * | ||
|  |  * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified | ||
|  |  * `ZyanString` instance. | ||
|  |  */ | ||
|  | ZYAN_INLINE ZyanStatus ZydisStringAppendDecS(ZyanString* string, ZyanI64 value, | ||
|  |     ZyanU8 padding_length, ZyanBool force_sign, const ZyanStringView* prefix, | ||
|  |     const ZyanStringView* suffix) | ||
|  | { | ||
|  |     static const ZydisShortString str_add = ZYDIS_MAKE_SHORTSTRING("+"); | ||
|  |     static const ZydisShortString str_sub = ZYDIS_MAKE_SHORTSTRING("-"); | ||
|  | 
 | ||
|  |     if (value < 0) | ||
|  |     { | ||
|  |         ZYAN_CHECK(ZydisStringAppendShort(string, &str_sub)); | ||
|  |         if (prefix) | ||
|  |         { | ||
|  |             ZYAN_CHECK(ZydisStringAppend(string, prefix)); | ||
|  |         } | ||
|  |         return ZydisStringAppendDecU(string, ZyanAbsI64(value), padding_length, | ||
|  |             (const ZyanStringView*)ZYAN_NULL, suffix); | ||
|  |     } | ||
|  | 
 | ||
|  |     if (force_sign) | ||
|  |     { | ||
|  |         ZYAN_ASSERT(value >= 0); | ||
|  |         ZYAN_CHECK(ZydisStringAppendShort(string, &str_add)); | ||
|  |     } | ||
|  |     return ZydisStringAppendDecU(string, value, padding_length, prefix, suffix); | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Formats the given unsigned ordinal `value` to its hexadecimal text-representation and | ||
|  |  * appends it to the `string`. | ||
|  |  * | ||
|  |  * @param   string                  A pointer to the `ZyanString` instance. | ||
|  |  * @param   value                   The value to append. | ||
|  |  * @param   padding_length          Pads the converted value with leading zeros if the number of | ||
|  |  *                                  chars is less than the `padding_length`. | ||
|  |  * @param   force_leading_number    Enable this option to prepend a leading `0` if the first | ||
|  |  *                                  character is non-numeric. | ||
|  |  * @param   uppercase               Enable this option to use uppercase letters ('A'-'F') instead | ||
|  |  *                                  of lowercase ones ('a'-'f'). | ||
|  |  * @param   prefix                  The string to use as prefix or `ZYAN_NULL`, if not needed. | ||
|  |  * @param   suffix                  The string to use as suffix or `ZYAN_NULL`, if not needed. | ||
|  |  * | ||
|  |  * @return  A zyan status code. | ||
|  |  * | ||
|  |  * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified | ||
|  |  * `ZyanString` instance. | ||
|  |  */ | ||
|  | ZyanStatus ZydisStringAppendHexU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length, | ||
|  |     ZyanBool force_leading_number, ZyanBool uppercase, const ZyanStringView* prefix, | ||
|  |     const ZyanStringView* suffix); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Formats the given signed ordinal `value` to its hexadecimal text-representation and | ||
|  |  * appends it to the `string`. | ||
|  |  * | ||
|  |  * @param   string                  A pointer to the `ZyanString` instance. | ||
|  |  * @param   value                   The value to append. | ||
|  |  * @param   padding_length          Padds the converted value with leading zeros, if the number of | ||
|  |  *                                  chars is less than the `padding_length` (the sign char does not | ||
|  |  *                                  count). | ||
|  |  * @param   force_leading_number    Enable this option to prepend a leading `0`, if the first | ||
|  |  *                                  character is non-numeric. | ||
|  |  * @param   uppercase               Enable this option to use uppercase letters ('A'-'F') instead | ||
|  |  *                                  of lowercase ones ('a'-'f'). | ||
|  |  * @param   force_sign              Enable this option to print the `+` sign for positive numbers. | ||
|  |  * @param   prefix                  The string to use as prefix or `ZYAN_NULL`, if not needed. | ||
|  |  * @param   suffix                  The string to use as suffix or `ZYAN_NULL`, if not needed. | ||
|  |  * | ||
|  |  * @return  A zyan status code. | ||
|  |  * | ||
|  |  * This function will fail if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified | ||
|  |  * `ZyanString` instance. | ||
|  |  */ | ||
|  | ZYAN_INLINE ZyanStatus ZydisStringAppendHexS(ZyanString* string, ZyanI64 value, | ||
|  |     ZyanU8 padding_length, ZyanBool force_leading_number, ZyanBool uppercase, ZyanBool force_sign, | ||
|  |     const ZyanStringView* prefix, const ZyanStringView* suffix) | ||
|  | { | ||
|  |     static const ZydisShortString str_add = ZYDIS_MAKE_SHORTSTRING("+"); | ||
|  |     static const ZydisShortString str_sub = ZYDIS_MAKE_SHORTSTRING("-"); | ||
|  | 
 | ||
|  |     if (value < 0) | ||
|  |     { | ||
|  |         ZYAN_CHECK(ZydisStringAppendShort(string, &str_sub)); | ||
|  |         if (prefix) | ||
|  |         { | ||
|  |             ZYAN_CHECK(ZydisStringAppend(string, prefix)); | ||
|  |         } | ||
|  |         return ZydisStringAppendHexU(string, ZyanAbsI64(value), padding_length, | ||
|  |             force_leading_number, uppercase, (const ZyanStringView*)ZYAN_NULL, suffix); | ||
|  |     } | ||
|  | 
 | ||
|  |     if (force_sign) | ||
|  |     { | ||
|  |         ZYAN_ASSERT(value >= 0); | ||
|  |         ZYAN_CHECK(ZydisStringAppendShort(string, &str_add)); | ||
|  |     } | ||
|  |     return ZydisStringAppendHexU(string, value, padding_length, force_leading_number, uppercase, | ||
|  |         prefix, suffix); | ||
|  | } | ||
|  | 
 | ||
|  | /* ---------------------------------------------------------------------------------------------- */ | ||
|  | 
 | ||
|  | /* ============================================================================================== */ | ||
|  | 
 | ||
|  | #ifdef __cplusplus
 | ||
|  | } | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #endif // ZYDIS_INTERNAL_STRING_H
 |