duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

String.c (13740B)


      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 #include <Zydis/Internal/String.h>
     28 
     29 /* ============================================================================================== */
     30 /* Constants                                                                                      */
     31 /* ============================================================================================== */
     32 
     33 /* ---------------------------------------------------------------------------------------------- */
     34 /* Defines                                                                                        */
     35 /* ---------------------------------------------------------------------------------------------- */
     36 
     37 #define ZYDIS_MAXCHARS_DEC_32 10
     38 #define ZYDIS_MAXCHARS_DEC_64 20
     39 #define ZYDIS_MAXCHARS_HEX_32  8
     40 #define ZYDIS_MAXCHARS_HEX_64 16
     41 
     42 /* ---------------------------------------------------------------------------------------------- */
     43 /* Lookup Tables                                                                                  */
     44 /* ---------------------------------------------------------------------------------------------- */
     45 
     46 static const char* const DECIMAL_LOOKUP =
     47     "00010203040506070809"
     48     "10111213141516171819"
     49     "20212223242526272829"
     50     "30313233343536373839"
     51     "40414243444546474849"
     52     "50515253545556575859"
     53     "60616263646566676869"
     54     "70717273747576777879"
     55     "80818283848586878889"
     56     "90919293949596979899";
     57 
     58 /* ---------------------------------------------------------------------------------------------- */
     59 
     60 /* ============================================================================================== */
     61 /* Internal Functions                                                                             */
     62 /* ============================================================================================== */
     63 
     64 /* ---------------------------------------------------------------------------------------------- */
     65 /* Decimal                                                                                        */
     66 /* ---------------------------------------------------------------------------------------------- */
     67 
     68 #if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN) || defined(ZYAN_WASM) || defined(ZYAN_PPC)
     69 ZyanStatus ZydisStringAppendDecU32(ZyanString* string, ZyanU32 value, ZyanU8 padding_length)
     70 {
     71     ZYAN_ASSERT(string);
     72     ZYAN_ASSERT(!string->vector.allocator);
     73 
     74     char buffer[ZYDIS_MAXCHARS_DEC_32];
     75     char *buffer_end = &buffer[ZYDIS_MAXCHARS_DEC_32];
     76     char *buffer_write_pointer = buffer_end;
     77     while (value >= 100)
     78     {
     79         const ZyanU32 value_old = value;
     80         buffer_write_pointer -= 2;
     81         value /= 100;
     82         ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[(value_old - (value * 100)) * 2], 2);
     83     }
     84     buffer_write_pointer -= 2;
     85     ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[value * 2], 2);
     86 
     87     const ZyanUSize offset_odd    = (ZyanUSize)(value < 10);
     88     const ZyanUSize length_number = buffer_end - buffer_write_pointer - offset_odd;
     89     const ZyanUSize length_total  = ZYAN_MAX(length_number, padding_length);
     90     const ZyanUSize length_target = string->vector.size;
     91 
     92     if (string->vector.size + length_total > string->vector.capacity)
     93     {
     94         return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
     95     }
     96 
     97     ZyanUSize offset_write = 0;
     98     if (padding_length > length_number)
     99     {
    100         offset_write = padding_length - length_number;
    101         ZYAN_MEMSET((char*)string->vector.data + length_target - 1, '0', offset_write);
    102     }
    103 
    104     ZYAN_MEMCPY((char*)string->vector.data + length_target + offset_write - 1,
    105         buffer_write_pointer + offset_odd, length_number);
    106     string->vector.size = length_target + length_total;
    107     ZYDIS_STRING_NULLTERMINATE(string);
    108 
    109     return ZYAN_STATUS_SUCCESS;
    110 }
    111 #endif
    112 
    113 ZyanStatus ZydisStringAppendDecU64(ZyanString* string, ZyanU64 value, ZyanU8 padding_length)
    114 {
    115     ZYAN_ASSERT(string);
    116     ZYAN_ASSERT(!string->vector.allocator);
    117 
    118     char buffer[ZYDIS_MAXCHARS_DEC_64];
    119     char *buffer_end = &buffer[ZYDIS_MAXCHARS_DEC_64];
    120     char *buffer_write_pointer = buffer_end;
    121     while (value >= 100)
    122     {
    123         const ZyanU64 value_old = value;
    124         buffer_write_pointer -= 2;
    125         value /= 100;
    126         ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[(value_old - (value * 100)) * 2], 2);
    127     }
    128     buffer_write_pointer -= 2;
    129     ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[value * 2], 2);
    130 
    131     const ZyanUSize offset_odd    = (ZyanUSize)(value < 10);
    132     const ZyanUSize length_number = buffer_end - buffer_write_pointer - offset_odd;
    133     const ZyanUSize length_total  = ZYAN_MAX(length_number, padding_length);
    134     const ZyanUSize length_target = string->vector.size;
    135 
    136     if (string->vector.size + length_total > string->vector.capacity)
    137     {
    138         return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
    139     }
    140 
    141     ZyanUSize offset_write = 0;
    142     if (padding_length > length_number)
    143     {
    144         offset_write = padding_length - length_number;
    145         ZYAN_MEMSET((char*)string->vector.data + length_target - 1, '0', offset_write);
    146     }
    147 
    148     ZYAN_MEMCPY((char*)string->vector.data + length_target + offset_write - 1,
    149         buffer_write_pointer + offset_odd, length_number);
    150     string->vector.size = length_target + length_total;
    151     ZYDIS_STRING_NULLTERMINATE(string);
    152 
    153     return ZYAN_STATUS_SUCCESS;
    154 }
    155 
    156 /* ---------------------------------------------------------------------------------------------- */
    157 /* Hexadecimal                                                                                    */
    158 /* ---------------------------------------------------------------------------------------------- */
    159 
    160 #if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN) || defined(ZYAN_WASM) || defined(ZYAN_PPC)
    161 ZyanStatus ZydisStringAppendHexU32(ZyanString* string, ZyanU32 value, ZyanU8 padding_length,
    162     ZyanBool force_leading_number, ZyanBool uppercase)
    163 {
    164     ZYAN_ASSERT(string);
    165     ZYAN_ASSERT(!string->vector.allocator);
    166 
    167     const ZyanUSize len = string->vector.size;
    168     const ZyanUSize remaining = string->vector.capacity - string->vector.size;
    169 
    170     if (remaining < (ZyanUSize)padding_length)
    171     {
    172         return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
    173     }
    174 
    175     if (!value)
    176     {
    177         const ZyanU8 n = (padding_length ? padding_length : 1);
    178 
    179         if (remaining < (ZyanUSize)n)
    180         {
    181             return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
    182         }
    183 
    184         ZYAN_MEMSET((char*)string->vector.data + len - 1, '0', n);
    185         string->vector.size = len + n;
    186         ZYDIS_STRING_NULLTERMINATE(string);
    187 
    188         return ZYAN_STATUS_SUCCESS;
    189     }
    190 
    191     ZyanU8 n = 0;
    192     char* buffer = ZYAN_NULL;
    193     for (ZyanI8 i = ZYDIS_MAXCHARS_HEX_32 - 1; i >= 0; --i)
    194     {
    195         const ZyanU8 v = (value >> i * 4) & 0x0F;
    196         if (!n)
    197         {
    198             if (!v)
    199             {
    200                 continue;
    201             }
    202             const ZyanU8 zero = force_leading_number && (v > 9) && (padding_length <= i) ? 1 : 0;
    203             if (remaining <= (ZyanUSize)i + zero)
    204             {
    205                 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
    206             }
    207             buffer = (char*)string->vector.data + len - 1;
    208             if (zero)
    209             {
    210                 buffer[n++] = '0';
    211             }
    212             if (padding_length > i)
    213             {
    214                 n = padding_length - i - 1;
    215                 ZYAN_MEMSET(buffer, '0', n);
    216             }
    217         }
    218         ZYAN_ASSERT(buffer);
    219         if (uppercase)
    220         {
    221             buffer[n++] = "0123456789ABCDEF"[v];
    222         } else
    223         {
    224             buffer[n++] = "0123456789abcdef"[v];
    225         }
    226     }
    227     string->vector.size = len + n;
    228     ZYDIS_STRING_NULLTERMINATE(string);
    229 
    230     return ZYAN_STATUS_SUCCESS;
    231 }
    232 #endif
    233 
    234 ZyanStatus ZydisStringAppendHexU64(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
    235     ZyanBool force_leading_number, ZyanBool uppercase)
    236 {
    237     ZYAN_ASSERT(string);
    238     ZYAN_ASSERT(!string->vector.allocator);
    239 
    240     const ZyanUSize len = string->vector.size;
    241     const ZyanUSize remaining = string->vector.capacity - string->vector.size;
    242 
    243     if (remaining < (ZyanUSize)padding_length)
    244     {
    245         return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
    246     }
    247 
    248     if (!value)
    249     {
    250         const ZyanU8 n = (padding_length ? padding_length : 1);
    251 
    252         if (remaining < (ZyanUSize)n)
    253         {
    254             return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
    255         }
    256 
    257         ZYAN_MEMSET((char*)string->vector.data + len - 1, '0', n);
    258         string->vector.size = len + n;
    259         ZYDIS_STRING_NULLTERMINATE(string);
    260 
    261         return ZYAN_STATUS_SUCCESS;
    262     }
    263 
    264     ZyanU8 n = 0;
    265     char* buffer = ZYAN_NULL;
    266     for (ZyanI8 i = ((value & 0xFFFFFFFF00000000) ?
    267         ZYDIS_MAXCHARS_HEX_64 : ZYDIS_MAXCHARS_HEX_32) - 1; i >= 0; --i)
    268     {
    269         const ZyanU8 v = (value >> i * 4) & 0x0F;
    270         if (!n)
    271         {
    272             if (!v)
    273             {
    274                 continue;
    275             }
    276             const ZyanU8 zero = force_leading_number && (v > 9) && (padding_length <= i) ? 1 : 0;
    277             if (remaining <= (ZyanUSize)i + zero)
    278             {
    279                 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
    280             }
    281             buffer = (char*)string->vector.data + len - 1;
    282             if (zero)
    283             {
    284                 buffer[n++] = '0';
    285             }
    286             if (padding_length > i)
    287             {
    288                 n = padding_length - i - 1;
    289                 ZYAN_MEMSET(buffer, '0', n);
    290             }
    291         }
    292         ZYAN_ASSERT(buffer);
    293         if (uppercase)
    294         {
    295             buffer[n++] = "0123456789ABCDEF"[v];
    296         } else
    297         {
    298             buffer[n++] = "0123456789abcdef"[v];
    299         }
    300     }
    301     string->vector.size = len + n;
    302     ZYDIS_STRING_NULLTERMINATE(string);
    303 
    304     return ZYAN_STATUS_SUCCESS;
    305 }
    306 
    307 /* ---------------------------------------------------------------------------------------------- */
    308 
    309 /* ============================================================================================== */
    310 /* Public Functions                                                                               */
    311 /* ============================================================================================== */
    312 
    313 /* ---------------------------------------------------------------------------------------------- */
    314 /* Formatting                                                                                     */
    315 /* ---------------------------------------------------------------------------------------------- */
    316 
    317 ZyanStatus ZydisStringAppendDecU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
    318     const ZyanStringView* prefix, const ZyanStringView* suffix)
    319 {
    320     if (prefix)
    321     {
    322         ZYAN_CHECK(ZydisStringAppend(string, prefix));
    323     }
    324 
    325 #if defined(ZYAN_X64) || defined(ZYAN_AARCH64) || defined(ZYAN_PPC64) || defined(ZYAN_RISCV64)
    326     ZYAN_CHECK(ZydisStringAppendDecU64(string, value, padding_length));
    327 #else
    328     if (value & 0xFFFFFFFF00000000)
    329     {
    330         ZYAN_CHECK(ZydisStringAppendDecU64(string, value, padding_length));
    331     }
    332     ZYAN_CHECK(ZydisStringAppendDecU32(string, (ZyanU32)value, padding_length));
    333 #endif
    334 
    335     if (suffix)
    336     {
    337         return ZydisStringAppend(string, suffix);
    338     }
    339     return ZYAN_STATUS_SUCCESS;
    340 }
    341 
    342 ZyanStatus ZydisStringAppendHexU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
    343     ZyanBool force_leading_number, ZyanBool uppercase, const ZyanStringView* prefix,
    344     const ZyanStringView* suffix)
    345 {
    346     if (prefix)
    347     {
    348         ZYAN_CHECK(ZydisStringAppend(string, prefix));
    349     }
    350 
    351 #if defined(ZYAN_X64) || defined(ZYAN_AARCH64) || defined(ZYAN_PPC64) || defined(ZYAN_RISCV64)
    352     ZYAN_CHECK(ZydisStringAppendHexU64(string, value, padding_length, force_leading_number,
    353         uppercase));
    354 #else
    355     if (value & 0xFFFFFFFF00000000)
    356     {
    357         ZYAN_CHECK(ZydisStringAppendHexU64(string, value, padding_length, force_leading_number,
    358             uppercase));
    359     }
    360     else
    361     {
    362         ZYAN_CHECK(ZydisStringAppendHexU32(string, (ZyanU32)value, padding_length,
    363             force_leading_number, uppercase));
    364     }
    365 #endif
    366 
    367     if (suffix)
    368     {
    369         return ZydisStringAppend(string, suffix);
    370     }
    371     return ZYAN_STATUS_SUCCESS;
    372 }
    373 
    374 /* ---------------------------------------------------------------------------------------------- */
    375 
    376 /* ============================================================================================== */