xref: /haiku/src/libs/zydis/Zydis/String.c (revision caed67a8cba83913b9c21ac2b06ebc6bd1cb3111)
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 static 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 static 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         ZYAN_DIV64(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 static 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 static 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) || defined(ZYAN_LOONGARCH)
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) || defined(ZYAN_LOONGARCH)
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 /* ============================================================================================== */
377