tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

String.h (18263B)


      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 /**
     28 * @file
     29 * Provides some internal, more performant, but unsafe helper functions for the `ZyanString`
     30 * data-type.
     31 *
     32 * Most of these functions are very similar to the ones in `Zycore/String.h`, but inlined and
     33 * without optional overhead like parameter-validation checks, etc ...
     34 *
     35 * The `ZyanString` data-type is able to dynamically allocate memory on the heap, but as `Zydis` is
     36 * designed to be a non-'malloc'ing library, all functions in this file assume that the instances
     37 * they are operating on are created with a user-defined static-buffer.
     38 */
     39 
     40 #ifndef ZYDIS_INTERNAL_STRING_H
     41 #define ZYDIS_INTERNAL_STRING_H
     42 
     43 #include "zydis/Zycore/LibC.h"
     44 #include "zydis/Zycore/String.h"
     45 #include "zydis/Zycore/Types.h"
     46 #include "zydis/Zycore/Format.h"
     47 #include "zydis/Zydis/ShortString.h"
     48 #include "zydis/Zycore/Defines.h"
     49 #include "zydis/Zycore/Status.h"
     50 #include "zydis/Zycore/Vector.h"
     51 
     52 #ifdef __cplusplus
     53 extern "C" {
     54 #endif
     55 
     56 /* ============================================================================================== */
     57 /* Enums and types                                                                                */
     58 /* ============================================================================================== */
     59 
     60 /* ---------------------------------------------------------------------------------------------- */
     61 /* Letter Case                                                                                    */
     62 /* ---------------------------------------------------------------------------------------------- */
     63 
     64 /**
     65 * Defines the `ZydisLetterCase` enum.
     66 */
     67 typedef enum ZydisLetterCase_
     68 {
     69    /**
     70     * Uses the given text "as is".
     71     */
     72    ZYDIS_LETTER_CASE_DEFAULT,
     73    /**
     74     * Converts the given text to lowercase letters.
     75     */
     76    ZYDIS_LETTER_CASE_LOWER,
     77    /**
     78     * Converts the given text to uppercase letters.
     79     */
     80    ZYDIS_LETTER_CASE_UPPER,
     81 
     82    /**
     83     * Maximum value of this enum.
     84     */
     85    ZYDIS_LETTER_CASE_MAX_VALUE = ZYDIS_LETTER_CASE_UPPER,
     86    /**
     87     * The minimum number of bits required to represent all values of this enum.
     88     */
     89    ZYDIS_LETTER_CASE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_LETTER_CASE_MAX_VALUE)
     90 } ZydisLetterCase;
     91 
     92 /* ---------------------------------------------------------------------------------------------- */
     93 
     94 /* ============================================================================================== */
     95 /* Macros                                                                                         */
     96 /* ============================================================================================== */
     97 
     98 /* ---------------------------------------------------------------------------------------------- */
     99 /* Internal macros                                                                                */
    100 /* ---------------------------------------------------------------------------------------------- */
    101 
    102 /**
    103 * Checks for a terminating '\0' character at the end of the string data.
    104 */
    105 #define ZYDIS_STRING_ASSERT_NULLTERMINATION(string) \
    106      ZYAN_ASSERT(*(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) == '\0');
    107 
    108 /**
    109 * Writes a terminating '\0' character at the end of the string data.
    110 */
    111 #define ZYDIS_STRING_NULLTERMINATE(string) \
    112      *(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) = '\0';
    113 
    114 /* ---------------------------------------------------------------------------------------------- */
    115 
    116 /* ============================================================================================== */
    117 /* Internal Functions                                                                             */
    118 /* ============================================================================================== */
    119 
    120 /* ---------------------------------------------------------------------------------------------- */
    121 /* Appending                                                                                      */
    122 /* ---------------------------------------------------------------------------------------------- */
    123 
    124 /**
    125 * Appends the content of the source string to the end of the destination string.
    126 *
    127 * @param   destination The destination string.
    128 * @param   source      The source string.
    129 *
    130 * @return  A zyan status code.
    131 */
    132 ZYAN_INLINE ZyanStatus ZydisStringAppend(ZyanString* destination, const ZyanStringView* source)
    133 {
    134    ZYAN_ASSERT(destination && source);
    135    ZYAN_ASSERT(!destination->vector.allocator);
    136    ZYAN_ASSERT(destination->vector.size && source->string.vector.size);
    137 
    138    if (destination->vector.size + source->string.vector.size - 1 > destination->vector.capacity)
    139    {
    140        return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
    141    }
    142 
    143    ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1,
    144        source->string.vector.data, source->string.vector.size - 1);
    145 
    146    destination->vector.size += source->string.vector.size - 1;
    147    ZYDIS_STRING_NULLTERMINATE(destination);
    148 
    149    return ZYAN_STATUS_SUCCESS;
    150 }
    151 
    152 /**
    153 * Appends the content of the source string to the end of the destination
    154 * string, converting the characters to the specified letter-case.
    155 *
    156 * @param   destination The destination string.
    157 * @param   source      The source string.
    158 * @param   letter_case The desired letter-case.
    159 *
    160 * @return  A zyan status code.
    161 */
    162 ZYAN_INLINE ZyanStatus ZydisStringAppendCase(ZyanString* destination, const ZyanStringView* source,
    163    ZydisLetterCase letter_case)
    164 {
    165    ZYAN_ASSERT(destination && source);
    166    ZYAN_ASSERT(!destination->vector.allocator);
    167    ZYAN_ASSERT(destination->vector.size && source->string.vector.size);
    168 
    169    if (destination->vector.size + source->string.vector.size - 1 > destination->vector.capacity)
    170    {
    171        return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
    172    }
    173 
    174    ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1,
    175        source->string.vector.data, source->string.vector.size - 1);
    176 
    177    switch (letter_case)
    178    {
    179    case ZYDIS_LETTER_CASE_DEFAULT:
    180        break;
    181    case ZYDIS_LETTER_CASE_LOWER:
    182    {
    183        const ZyanUSize index = destination->vector.size - 1;
    184        const ZyanUSize count = source->string.vector.size - 1;
    185        char* s = (char*)destination->vector.data + index;
    186        for (ZyanUSize i = index; i < index + count; ++i)
    187        {
    188            const char c = *s;
    189            if ((c >= 'A') && (c <= 'Z'))
    190            {
    191                *s = c | 32;
    192            }
    193            ++s;
    194        }
    195        break;
    196    }
    197    case ZYDIS_LETTER_CASE_UPPER:
    198    {
    199        const ZyanUSize index = destination->vector.size - 1;
    200        const ZyanUSize count = source->string.vector.size - 1;
    201        char* s = (char*)destination->vector.data + index;
    202        for (ZyanUSize i = index; i < index + count; ++i)
    203        {
    204            const char c = *s;
    205            if ((c >= 'a') && (c <= 'z'))
    206            {
    207                *s = c & ~32;
    208            }
    209            ++s;
    210        }
    211        break;
    212    }
    213    default:
    214        ZYAN_UNREACHABLE;
    215    }
    216 
    217    destination->vector.size += source->string.vector.size - 1;
    218    ZYDIS_STRING_NULLTERMINATE(destination);
    219 
    220    return ZYAN_STATUS_SUCCESS;
    221 }
    222 
    223 /**
    224 * Appends the content of the source short-string to the end of the destination string.
    225 *
    226 * @param   destination The destination string.
    227 * @param   source      The source string.
    228 *
    229 * @return  A zyan status code.
    230 */
    231 ZYAN_INLINE ZyanStatus ZydisStringAppendShort(ZyanString* destination,
    232    const ZydisShortString* source)
    233 {
    234    ZYAN_ASSERT(destination && source);
    235    ZYAN_ASSERT(!destination->vector.allocator);
    236    ZYAN_ASSERT(destination->vector.size && source->size);
    237 
    238    if (destination->vector.size + source->size > destination->vector.capacity)
    239    {
    240        return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
    241    }
    242 
    243    ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1, source->data,
    244        (ZyanUSize)source->size + 1);
    245 
    246    destination->vector.size += source->size;
    247    ZYDIS_STRING_ASSERT_NULLTERMINATION(destination);
    248 
    249    return ZYAN_STATUS_SUCCESS;
    250 }
    251 
    252 /**
    253 * Appends the content of the source short-string to the end of the destination string,
    254 * converting the characters to the specified letter-case.
    255 *
    256 * @param   destination The destination string.
    257 * @param   source      The source string.
    258 * @param   letter_case The desired letter-case.
    259 *
    260 * @return  A zyan status code.
    261 */
    262 ZYAN_INLINE ZyanStatus ZydisStringAppendShortCase(ZyanString* destination,
    263    const ZydisShortString* source, ZydisLetterCase letter_case)
    264 {
    265    ZYAN_ASSERT(destination && source);
    266    ZYAN_ASSERT(!destination->vector.allocator);
    267    ZYAN_ASSERT(destination->vector.size && source->size);
    268 
    269    if (destination->vector.size + source->size > destination->vector.capacity)
    270    {
    271        return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
    272    }
    273 
    274    ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1, source->data,
    275        (ZyanUSize)source->size + 1);
    276 
    277    switch (letter_case)
    278    {
    279    case ZYDIS_LETTER_CASE_DEFAULT:
    280        break;
    281    case ZYDIS_LETTER_CASE_LOWER:
    282    {
    283        const ZyanUSize index = destination->vector.size - 1;
    284        const ZyanUSize count = source->size;
    285        char* s = (char*)destination->vector.data + index;
    286        for (ZyanUSize i = index; i < index + count; ++i)
    287        {
    288            const char c = *s;
    289            if ((c >= 'A') && (c <= 'Z'))
    290            {
    291                *s = c | 32;
    292            }
    293            ++s;
    294        }
    295        break;
    296    }
    297    case ZYDIS_LETTER_CASE_UPPER:
    298    {
    299        const ZyanUSize index = destination->vector.size - 1;
    300        const ZyanUSize count = source->size;
    301        char* s = (char*)destination->vector.data + index;
    302        for (ZyanUSize i = index; i < index + count; ++i)
    303        {
    304            const char c = *s;
    305            if ((c >= 'a') && (c <= 'z'))
    306            {
    307                *s = c & ~32;
    308            }
    309            ++s;
    310        }
    311        break;
    312    }
    313    default:
    314        ZYAN_UNREACHABLE;
    315    }
    316 
    317    destination->vector.size += source->size;
    318    ZYDIS_STRING_ASSERT_NULLTERMINATION(destination);
    319 
    320    return ZYAN_STATUS_SUCCESS;
    321 }
    322 
    323 /* ---------------------------------------------------------------------------------------------- */
    324 /* Formatting                                                                                     */
    325 /* ---------------------------------------------------------------------------------------------- */
    326 
    327 /**
    328 * Formats the given unsigned ordinal `value` to its decimal text-representation and
    329 * appends it to the `string`.
    330 *
    331 * @param   string          A pointer to the `ZyanString` instance.
    332 * @param   value           The value to append.
    333 * @param   padding_length  Padds the converted value with leading zeros, if the number of chars is
    334 *                          less than the `padding_length`.
    335 * @param   prefix          The string to use as prefix or `ZYAN_NULL`, if not needed.
    336 * @param   suffix          The string to use as suffix or `ZYAN_NULL`, if not needed.
    337 *
    338 * @return  A zyan status code.
    339 *
    340 * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
    341 * `ZyanString` instance.
    342 */
    343 ZyanStatus ZydisStringAppendDecU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
    344    const ZyanStringView* prefix, const ZyanStringView* suffix);
    345 
    346 /**
    347 * Formats the given signed ordinal `value` to its decimal text-representation and
    348 * appends it to the `string`.
    349 *
    350 * @param   string          A pointer to the `ZyanString` instance.
    351 * @param   value           The value to append.
    352 * @param   padding_length  Padds the converted value with leading zeros, if the number of chars is
    353 *                          less than the `padding_length`.
    354 * @param   force_sign      Enable this option to print the `+` sign for positive numbers.
    355 * @param   prefix          The string to use as prefix or `ZYAN_NULL`, if not needed.
    356 * @param   suffix          The string to use as suffix or `ZYAN_NULL`, if not needed.
    357 *
    358 * @return  A zyan status code.
    359 *
    360 * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
    361 * `ZyanString` instance.
    362 */
    363 ZYAN_INLINE ZyanStatus ZydisStringAppendDecS(ZyanString* string, ZyanI64 value,
    364    ZyanU8 padding_length, ZyanBool force_sign, const ZyanStringView* prefix,
    365    const ZyanStringView* suffix)
    366 {
    367    static const ZydisShortString str_add = ZYDIS_MAKE_SHORTSTRING("+");
    368    static const ZydisShortString str_sub = ZYDIS_MAKE_SHORTSTRING("-");
    369 
    370    if (value < 0)
    371    {
    372        ZYAN_CHECK(ZydisStringAppendShort(string, &str_sub));
    373        if (prefix)
    374        {
    375            ZYAN_CHECK(ZydisStringAppend(string, prefix));
    376        }
    377        return ZydisStringAppendDecU(string, ZyanAbsI64(value), padding_length,
    378            (const ZyanStringView*)ZYAN_NULL, suffix);
    379    }
    380 
    381    if (force_sign)
    382    {
    383        ZYAN_ASSERT(value >= 0);
    384        ZYAN_CHECK(ZydisStringAppendShort(string, &str_add));
    385    }
    386    return ZydisStringAppendDecU(string, value, padding_length, prefix, suffix);
    387 }
    388 
    389 /**
    390 * Formats the given unsigned ordinal `value` to its hexadecimal text-representation and
    391 * appends it to the `string`.
    392 *
    393 * @param   string                  A pointer to the `ZyanString` instance.
    394 * @param   value                   The value to append.
    395 * @param   padding_length          Pads the converted value with leading zeros if the number of
    396 *                                  chars is less than the `padding_length`.
    397 * @param   force_leading_number    Enable this option to prepend a leading `0` if the first
    398 *                                  character is non-numeric.
    399 * @param   uppercase               Enable this option to use uppercase letters ('A'-'F') instead
    400 *                                  of lowercase ones ('a'-'f').
    401 * @param   prefix                  The string to use as prefix or `ZYAN_NULL`, if not needed.
    402 * @param   suffix                  The string to use as suffix or `ZYAN_NULL`, if not needed.
    403 *
    404 * @return  A zyan status code.
    405 *
    406 * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
    407 * `ZyanString` instance.
    408 */
    409 ZyanStatus ZydisStringAppendHexU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
    410    ZyanBool force_leading_number, ZyanBool uppercase, const ZyanStringView* prefix,
    411    const ZyanStringView* suffix);
    412 
    413 /**
    414 * Formats the given signed ordinal `value` to its hexadecimal text-representation and
    415 * appends it to the `string`.
    416 *
    417 * @param   string                  A pointer to the `ZyanString` instance.
    418 * @param   value                   The value to append.
    419 * @param   padding_length          Padds the converted value with leading zeros, if the number of
    420 *                                  chars is less than the `padding_length` (the sign char does not
    421 *                                  count).
    422 * @param   force_leading_number    Enable this option to prepend a leading `0`, if the first
    423 *                                  character is non-numeric.
    424 * @param   uppercase               Enable this option to use uppercase letters ('A'-'F') instead
    425 *                                  of lowercase ones ('a'-'f').
    426 * @param   force_sign              Enable this option to print the `+` sign for positive numbers.
    427 * @param   prefix                  The string to use as prefix or `ZYAN_NULL`, if not needed.
    428 * @param   suffix                  The string to use as suffix or `ZYAN_NULL`, if not needed.
    429 *
    430 * @return  A zyan status code.
    431 *
    432 * This function will fail if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
    433 * `ZyanString` instance.
    434 */
    435 ZYAN_INLINE ZyanStatus ZydisStringAppendHexS(ZyanString* string, ZyanI64 value,
    436    ZyanU8 padding_length, ZyanBool force_leading_number, ZyanBool uppercase, ZyanBool force_sign,
    437    const ZyanStringView* prefix, const ZyanStringView* suffix)
    438 {
    439    static const ZydisShortString str_add = ZYDIS_MAKE_SHORTSTRING("+");
    440    static const ZydisShortString str_sub = ZYDIS_MAKE_SHORTSTRING("-");
    441 
    442    if (value < 0)
    443    {
    444        ZYAN_CHECK(ZydisStringAppendShort(string, &str_sub));
    445        if (prefix)
    446        {
    447            ZYAN_CHECK(ZydisStringAppend(string, prefix));
    448        }
    449        return ZydisStringAppendHexU(string, ZyanAbsI64(value), padding_length,
    450            force_leading_number, uppercase, (const ZyanStringView*)ZYAN_NULL, suffix);
    451    }
    452 
    453    if (force_sign)
    454    {
    455        ZYAN_ASSERT(value >= 0);
    456        ZYAN_CHECK(ZydisStringAppendShort(string, &str_add));
    457    }
    458    return ZydisStringAppendHexU(string, value, padding_length, force_leading_number, uppercase,
    459        prefix, suffix);
    460 }
    461 
    462 /* ---------------------------------------------------------------------------------------------- */
    463 
    464 /* ============================================================================================== */
    465 
    466 #ifdef __cplusplus
    467 }
    468 #endif
    469 
    470 #endif // ZYDIS_INTERNAL_STRING_H