Path: blob/master/dep/zydis/include/Zydis/Internal/String.h
4219 views
/***************************************************************************************************12Zyan Disassembler Library (Zydis)34Original Author : Florian Bernd, Joel Hoener56* Permission is hereby granted, free of charge, to any person obtaining a copy7* of this software and associated documentation files (the "Software"), to deal8* in the Software without restriction, including without limitation the rights9* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell10* copies of the Software, and to permit persons to whom the Software is11* furnished to do so, subject to the following conditions:12*13* The above copyright notice and this permission notice shall be included in all14* copies or substantial portions of the Software.15*16* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR17* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,18* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE19* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER20* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,21* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE22* SOFTWARE.2324***************************************************************************************************/2526/**27* @file28* Provides some internal, more performant, but unsafe helper functions for the `ZyanString`29* data-type.30*31* Most of these functions are very similar to the ones in `Zycore/String.h`, but inlined and32* without optional overhead like parameter-validation checks, etc ...33*34* The `ZyanString` data-type is able to dynamically allocate memory on the heap, but as `Zydis` is35* designed to be a non-'malloc'ing library, all functions in this file assume that the instances36* they are operating on are created with a user-defined static-buffer.37*/3839#ifndef ZYDIS_INTERNAL_STRING_H40#define ZYDIS_INTERNAL_STRING_H4142#include <Zycore/LibC.h>43#include <Zycore/String.h>44#include <Zycore/Types.h>45#include <Zycore/Format.h>46#include <Zydis/ShortString.h>47#include <Zycore/Defines.h>48#include <Zycore/Status.h>49#include <Zycore/Vector.h>5051#ifdef __cplusplus52extern "C" {53#endif5455/* ============================================================================================== */56/* Enums and types */57/* ============================================================================================== */5859/* ---------------------------------------------------------------------------------------------- */60/* Letter Case */61/* ---------------------------------------------------------------------------------------------- */6263/**64* Defines the `ZydisLetterCase` enum.65*/66typedef enum ZydisLetterCase_67{68/**69* Uses the given text "as is".70*/71ZYDIS_LETTER_CASE_DEFAULT,72/**73* Converts the given text to lowercase letters.74*/75ZYDIS_LETTER_CASE_LOWER,76/**77* Converts the given text to uppercase letters.78*/79ZYDIS_LETTER_CASE_UPPER,8081/**82* Maximum value of this enum.83*/84ZYDIS_LETTER_CASE_MAX_VALUE = ZYDIS_LETTER_CASE_UPPER,85/**86* The minimum number of bits required to represent all values of this enum.87*/88ZYDIS_LETTER_CASE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_LETTER_CASE_MAX_VALUE)89} ZydisLetterCase;9091/* ---------------------------------------------------------------------------------------------- */9293/* ============================================================================================== */94/* Macros */95/* ============================================================================================== */9697/* ---------------------------------------------------------------------------------------------- */98/* Internal macros */99/* ---------------------------------------------------------------------------------------------- */100101/**102* Checks for a terminating '\0' character at the end of the string data.103*/104#define ZYDIS_STRING_ASSERT_NULLTERMINATION(string) \105ZYAN_ASSERT(*(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) == '\0');106107/**108* Writes a terminating '\0' character at the end of the string data.109*/110#define ZYDIS_STRING_NULLTERMINATE(string) \111*(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) = '\0';112113/* ---------------------------------------------------------------------------------------------- */114115/* ============================================================================================== */116/* Internal Functions */117/* ============================================================================================== */118119/* ---------------------------------------------------------------------------------------------- */120/* Appending */121/* ---------------------------------------------------------------------------------------------- */122123/**124* Appends the content of the source string to the end of the destination string.125*126* @param destination The destination string.127* @param source The source string.128*129* @return A zyan status code.130*/131ZYAN_INLINE ZyanStatus ZydisStringAppend(ZyanString* destination, const ZyanStringView* source)132{133ZYAN_ASSERT(destination && source);134ZYAN_ASSERT(!destination->vector.allocator);135ZYAN_ASSERT(destination->vector.size && source->string.vector.size);136137if (destination->vector.size + source->string.vector.size - 1 > destination->vector.capacity)138{139return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;140}141142ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1,143source->string.vector.data, source->string.vector.size - 1);144145destination->vector.size += source->string.vector.size - 1;146ZYDIS_STRING_NULLTERMINATE(destination);147148return ZYAN_STATUS_SUCCESS;149}150151/**152* Appends the content of the source string to the end of the destination153* string, converting the characters to the specified letter-case.154*155* @param destination The destination string.156* @param source The source string.157* @param letter_case The desired letter-case.158*159* @return A zyan status code.160*/161ZYAN_INLINE ZyanStatus ZydisStringAppendCase(ZyanString* destination, const ZyanStringView* source,162ZydisLetterCase letter_case)163{164ZYAN_ASSERT(destination && source);165ZYAN_ASSERT(!destination->vector.allocator);166ZYAN_ASSERT(destination->vector.size && source->string.vector.size);167168if (destination->vector.size + source->string.vector.size - 1 > destination->vector.capacity)169{170return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;171}172173ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1,174source->string.vector.data, source->string.vector.size - 1);175176switch (letter_case)177{178case ZYDIS_LETTER_CASE_DEFAULT:179break;180case ZYDIS_LETTER_CASE_LOWER:181{182const ZyanUSize index = destination->vector.size - 1;183const ZyanUSize count = source->string.vector.size - 1;184char* s = (char*)destination->vector.data + index;185for (ZyanUSize i = index; i < index + count; ++i)186{187const char c = *s;188if ((c >= 'A') && (c <= 'Z'))189{190*s = c | 32;191}192++s;193}194break;195}196case ZYDIS_LETTER_CASE_UPPER:197{198const ZyanUSize index = destination->vector.size - 1;199const ZyanUSize count = source->string.vector.size - 1;200char* s = (char*)destination->vector.data + index;201for (ZyanUSize i = index; i < index + count; ++i)202{203const char c = *s;204if ((c >= 'a') && (c <= 'z'))205{206*s = c & ~32;207}208++s;209}210break;211}212default:213ZYAN_UNREACHABLE;214}215216destination->vector.size += source->string.vector.size - 1;217ZYDIS_STRING_NULLTERMINATE(destination);218219return ZYAN_STATUS_SUCCESS;220}221222/**223* Appends the content of the source short-string to the end of the destination string.224*225* @param destination The destination string.226* @param source The source string.227*228* @return A zyan status code.229*/230ZYAN_INLINE ZyanStatus ZydisStringAppendShort(ZyanString* destination,231const ZydisShortString* source)232{233ZYAN_ASSERT(destination && source);234ZYAN_ASSERT(!destination->vector.allocator);235ZYAN_ASSERT(destination->vector.size && source->size);236237if (destination->vector.size + source->size > destination->vector.capacity)238{239return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;240}241242ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1, source->data,243(ZyanUSize)source->size + 1);244245destination->vector.size += source->size;246ZYDIS_STRING_ASSERT_NULLTERMINATION(destination);247248return ZYAN_STATUS_SUCCESS;249}250251/**252* Appends the content of the source short-string to the end of the destination string,253* converting the characters to the specified letter-case.254*255* @param destination The destination string.256* @param source The source string.257* @param letter_case The desired letter-case.258*259* @return A zyan status code.260*/261ZYAN_INLINE ZyanStatus ZydisStringAppendShortCase(ZyanString* destination,262const ZydisShortString* source, ZydisLetterCase letter_case)263{264ZYAN_ASSERT(destination && source);265ZYAN_ASSERT(!destination->vector.allocator);266ZYAN_ASSERT(destination->vector.size && source->size);267268if (destination->vector.size + source->size > destination->vector.capacity)269{270return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;271}272273ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1, source->data,274(ZyanUSize)source->size + 1);275276switch (letter_case)277{278case ZYDIS_LETTER_CASE_DEFAULT:279break;280case ZYDIS_LETTER_CASE_LOWER:281{282const ZyanUSize index = destination->vector.size - 1;283const ZyanUSize count = source->size;284char* s = (char*)destination->vector.data + index;285for (ZyanUSize i = index; i < index + count; ++i)286{287const char c = *s;288if ((c >= 'A') && (c <= 'Z'))289{290*s = c | 32;291}292++s;293}294break;295}296case ZYDIS_LETTER_CASE_UPPER:297{298const ZyanUSize index = destination->vector.size - 1;299const ZyanUSize count = source->size;300char* s = (char*)destination->vector.data + index;301for (ZyanUSize i = index; i < index + count; ++i)302{303const char c = *s;304if ((c >= 'a') && (c <= 'z'))305{306*s = c & ~32;307}308++s;309}310break;311}312default:313ZYAN_UNREACHABLE;314}315316destination->vector.size += source->size;317ZYDIS_STRING_ASSERT_NULLTERMINATION(destination);318319return ZYAN_STATUS_SUCCESS;320}321322/* ---------------------------------------------------------------------------------------------- */323/* Formatting */324/* ---------------------------------------------------------------------------------------------- */325326/**327* Formats the given unsigned ordinal `value` to its decimal text-representation and328* appends it to the `string`.329*330* @param string A pointer to the `ZyanString` instance.331* @param value The value to append.332* @param padding_length Padds the converted value with leading zeros, if the number of chars is333* less than the `padding_length`.334* @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed.335* @param suffix The string to use as suffix or `ZYAN_NULL`, if not needed.336*337* @return A zyan status code.338*339* This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified340* `ZyanString` instance.341*/342ZyanStatus ZydisStringAppendDecU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,343const ZyanStringView* prefix, const ZyanStringView* suffix);344345/**346* Formats the given signed ordinal `value` to its decimal text-representation and347* appends it to the `string`.348*349* @param string A pointer to the `ZyanString` instance.350* @param value The value to append.351* @param padding_length Padds the converted value with leading zeros, if the number of chars is352* less than the `padding_length`.353* @param force_sign Enable this option to print the `+` sign for positive numbers.354* @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed.355* @param suffix The string to use as suffix or `ZYAN_NULL`, if not needed.356*357* @return A zyan status code.358*359* This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified360* `ZyanString` instance.361*/362ZYAN_INLINE ZyanStatus ZydisStringAppendDecS(ZyanString* string, ZyanI64 value,363ZyanU8 padding_length, ZyanBool force_sign, const ZyanStringView* prefix,364const ZyanStringView* suffix)365{366static const ZydisShortString str_add = ZYDIS_MAKE_SHORTSTRING("+");367static const ZydisShortString str_sub = ZYDIS_MAKE_SHORTSTRING("-");368369if (value < 0)370{371ZYAN_CHECK(ZydisStringAppendShort(string, &str_sub));372if (prefix)373{374ZYAN_CHECK(ZydisStringAppend(string, prefix));375}376return ZydisStringAppendDecU(string, ZyanAbsI64(value), padding_length,377(const ZyanStringView*)ZYAN_NULL, suffix);378}379380if (force_sign)381{382ZYAN_ASSERT(value >= 0);383ZYAN_CHECK(ZydisStringAppendShort(string, &str_add));384}385return ZydisStringAppendDecU(string, value, padding_length, prefix, suffix);386}387388/**389* Formats the given unsigned ordinal `value` to its hexadecimal text-representation and390* appends it to the `string`.391*392* @param string A pointer to the `ZyanString` instance.393* @param value The value to append.394* @param padding_length Pads the converted value with leading zeros if the number of395* chars is less than the `padding_length`.396* @param force_leading_number Enable this option to prepend a leading `0` if the first397* character is non-numeric.398* @param uppercase Enable this option to use uppercase letters ('A'-'F') instead399* of lowercase ones ('a'-'f').400* @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed.401* @param suffix The string to use as suffix or `ZYAN_NULL`, if not needed.402*403* @return A zyan status code.404*405* This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified406* `ZyanString` instance.407*/408ZyanStatus ZydisStringAppendHexU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,409ZyanBool force_leading_number, ZyanBool uppercase, const ZyanStringView* prefix,410const ZyanStringView* suffix);411412/**413* Formats the given signed ordinal `value` to its hexadecimal text-representation and414* appends it to the `string`.415*416* @param string A pointer to the `ZyanString` instance.417* @param value The value to append.418* @param padding_length Padds the converted value with leading zeros, if the number of419* chars is less than the `padding_length` (the sign char does not420* count).421* @param force_leading_number Enable this option to prepend a leading `0`, if the first422* character is non-numeric.423* @param uppercase Enable this option to use uppercase letters ('A'-'F') instead424* of lowercase ones ('a'-'f').425* @param force_sign Enable this option to print the `+` sign for positive numbers.426* @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed.427* @param suffix The string to use as suffix or `ZYAN_NULL`, if not needed.428*429* @return A zyan status code.430*431* This function will fail if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified432* `ZyanString` instance.433*/434ZYAN_INLINE ZyanStatus ZydisStringAppendHexS(ZyanString* string, ZyanI64 value,435ZyanU8 padding_length, ZyanBool force_leading_number, ZyanBool uppercase, ZyanBool force_sign,436const ZyanStringView* prefix, const ZyanStringView* suffix)437{438static const ZydisShortString str_add = ZYDIS_MAKE_SHORTSTRING("+");439static const ZydisShortString str_sub = ZYDIS_MAKE_SHORTSTRING("-");440441if (value < 0)442{443ZYAN_CHECK(ZydisStringAppendShort(string, &str_sub));444if (prefix)445{446ZYAN_CHECK(ZydisStringAppend(string, prefix));447}448return ZydisStringAppendHexU(string, ZyanAbsI64(value), padding_length,449force_leading_number, uppercase, (const ZyanStringView*)ZYAN_NULL, suffix);450}451452if (force_sign)453{454ZYAN_ASSERT(value >= 0);455ZYAN_CHECK(ZydisStringAppendShort(string, &str_add));456}457return ZydisStringAppendHexU(string, value, padding_length, force_leading_number, uppercase,458prefix, suffix);459}460461/* ---------------------------------------------------------------------------------------------- */462463/* ============================================================================================== */464465#ifdef __cplusplus466}467#endif468469#endif // ZYDIS_INTERNAL_STRING_H470471472