tor-browser

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

Format.c (18068B)


      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 * 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) || defined(ZYAN_WASM) || defined(ZYAN_PPC)
     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 
    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) || defined(ZYAN_WASM) || defined(ZYAN_PPC)
    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 
    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 
    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 
    424 ZyanStatus ZyanStringAppendDecU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length)
    425 {
    426 #if defined(ZYAN_X64) || defined(ZYAN_AARCH64) || defined(ZYAN_PPC64) || defined(ZYAN_RISCV64) || defined(ZYAN_LOONGARCH)
    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 
    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, ZyanAbsI64(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 
    464 ZyanStatus ZyanStringAppendHexU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
    465    ZyanBool uppercase)
    466 {
    467 #if defined(ZYAN_X64) || defined(ZYAN_AARCH64) || defined(ZYAN_PPC64) || defined(ZYAN_RISCV64) || defined(ZYAN_LOONGARCH)
    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 
    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, ZyanAbsI64(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 /* ============================================================================================== */