/ externals / zydis / src / String.c
String.c
  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  /* ============================================================================================== */