xref: /openbmc/u-boot/lib/libavb/avb_util.c (revision 4ac5df4b)
1*897a1d94STom Rini // SPDX-License-Identifier: MIT
2d8f9d2afSIgor Opaniuk /*
3d8f9d2afSIgor Opaniuk  * Copyright (C) 2016 The Android Open Source Project
4d8f9d2afSIgor Opaniuk  */
5d8f9d2afSIgor Opaniuk 
6d8f9d2afSIgor Opaniuk #include "avb_util.h"
7d8f9d2afSIgor Opaniuk 
8d8f9d2afSIgor Opaniuk #include <stdarg.h>
9d8f9d2afSIgor Opaniuk 
avb_be32toh(uint32_t in)10d8f9d2afSIgor Opaniuk uint32_t avb_be32toh(uint32_t in) {
11d8f9d2afSIgor Opaniuk   uint8_t* d = (uint8_t*)&in;
12d8f9d2afSIgor Opaniuk   uint32_t ret;
13d8f9d2afSIgor Opaniuk   ret = ((uint32_t)d[0]) << 24;
14d8f9d2afSIgor Opaniuk   ret |= ((uint32_t)d[1]) << 16;
15d8f9d2afSIgor Opaniuk   ret |= ((uint32_t)d[2]) << 8;
16d8f9d2afSIgor Opaniuk   ret |= ((uint32_t)d[3]);
17d8f9d2afSIgor Opaniuk   return ret;
18d8f9d2afSIgor Opaniuk }
19d8f9d2afSIgor Opaniuk 
avb_be64toh(uint64_t in)20d8f9d2afSIgor Opaniuk uint64_t avb_be64toh(uint64_t in) {
21d8f9d2afSIgor Opaniuk   uint8_t* d = (uint8_t*)&in;
22d8f9d2afSIgor Opaniuk   uint64_t ret;
23d8f9d2afSIgor Opaniuk   ret = ((uint64_t)d[0]) << 56;
24d8f9d2afSIgor Opaniuk   ret |= ((uint64_t)d[1]) << 48;
25d8f9d2afSIgor Opaniuk   ret |= ((uint64_t)d[2]) << 40;
26d8f9d2afSIgor Opaniuk   ret |= ((uint64_t)d[3]) << 32;
27d8f9d2afSIgor Opaniuk   ret |= ((uint64_t)d[4]) << 24;
28d8f9d2afSIgor Opaniuk   ret |= ((uint64_t)d[5]) << 16;
29d8f9d2afSIgor Opaniuk   ret |= ((uint64_t)d[6]) << 8;
30d8f9d2afSIgor Opaniuk   ret |= ((uint64_t)d[7]);
31d8f9d2afSIgor Opaniuk   return ret;
32d8f9d2afSIgor Opaniuk }
33d8f9d2afSIgor Opaniuk 
34d8f9d2afSIgor Opaniuk /* Converts a 32-bit unsigned integer from host to big-endian byte order. */
avb_htobe32(uint32_t in)35d8f9d2afSIgor Opaniuk uint32_t avb_htobe32(uint32_t in) {
36d8f9d2afSIgor Opaniuk   union {
37d8f9d2afSIgor Opaniuk     uint32_t word;
38d8f9d2afSIgor Opaniuk     uint8_t bytes[4];
39d8f9d2afSIgor Opaniuk   } ret;
40d8f9d2afSIgor Opaniuk   ret.bytes[0] = (in >> 24) & 0xff;
41d8f9d2afSIgor Opaniuk   ret.bytes[1] = (in >> 16) & 0xff;
42d8f9d2afSIgor Opaniuk   ret.bytes[2] = (in >> 8) & 0xff;
43d8f9d2afSIgor Opaniuk   ret.bytes[3] = in & 0xff;
44d8f9d2afSIgor Opaniuk   return ret.word;
45d8f9d2afSIgor Opaniuk }
46d8f9d2afSIgor Opaniuk 
47d8f9d2afSIgor Opaniuk /* Converts a 64-bit unsigned integer from host to big-endian byte order. */
avb_htobe64(uint64_t in)48d8f9d2afSIgor Opaniuk uint64_t avb_htobe64(uint64_t in) {
49d8f9d2afSIgor Opaniuk   union {
50d8f9d2afSIgor Opaniuk     uint64_t word;
51d8f9d2afSIgor Opaniuk     uint8_t bytes[8];
52d8f9d2afSIgor Opaniuk   } ret;
53d8f9d2afSIgor Opaniuk   ret.bytes[0] = (in >> 56) & 0xff;
54d8f9d2afSIgor Opaniuk   ret.bytes[1] = (in >> 48) & 0xff;
55d8f9d2afSIgor Opaniuk   ret.bytes[2] = (in >> 40) & 0xff;
56d8f9d2afSIgor Opaniuk   ret.bytes[3] = (in >> 32) & 0xff;
57d8f9d2afSIgor Opaniuk   ret.bytes[4] = (in >> 24) & 0xff;
58d8f9d2afSIgor Opaniuk   ret.bytes[5] = (in >> 16) & 0xff;
59d8f9d2afSIgor Opaniuk   ret.bytes[6] = (in >> 8) & 0xff;
60d8f9d2afSIgor Opaniuk   ret.bytes[7] = in & 0xff;
61d8f9d2afSIgor Opaniuk   return ret.word;
62d8f9d2afSIgor Opaniuk }
63d8f9d2afSIgor Opaniuk 
avb_safe_memcmp(const void * s1,const void * s2,size_t n)64d8f9d2afSIgor Opaniuk int avb_safe_memcmp(const void* s1, const void* s2, size_t n) {
65d8f9d2afSIgor Opaniuk   const unsigned char* us1 = s1;
66d8f9d2afSIgor Opaniuk   const unsigned char* us2 = s2;
67d8f9d2afSIgor Opaniuk   int result = 0;
68d8f9d2afSIgor Opaniuk 
69d8f9d2afSIgor Opaniuk   if (0 == n) {
70d8f9d2afSIgor Opaniuk     return 0;
71d8f9d2afSIgor Opaniuk   }
72d8f9d2afSIgor Opaniuk 
73d8f9d2afSIgor Opaniuk   /*
74d8f9d2afSIgor Opaniuk    * Code snippet without data-dependent branch due to Nate Lawson
75d8f9d2afSIgor Opaniuk    * (nate@root.org) of Root Labs.
76d8f9d2afSIgor Opaniuk    */
77d8f9d2afSIgor Opaniuk   while (n--) {
78d8f9d2afSIgor Opaniuk     result |= *us1++ ^ *us2++;
79d8f9d2afSIgor Opaniuk   }
80d8f9d2afSIgor Opaniuk 
81d8f9d2afSIgor Opaniuk   return result != 0;
82d8f9d2afSIgor Opaniuk }
83d8f9d2afSIgor Opaniuk 
avb_safe_add_to(uint64_t * value,uint64_t value_to_add)84d8f9d2afSIgor Opaniuk bool avb_safe_add_to(uint64_t* value, uint64_t value_to_add) {
85d8f9d2afSIgor Opaniuk   uint64_t original_value;
86d8f9d2afSIgor Opaniuk 
87d8f9d2afSIgor Opaniuk   avb_assert(value != NULL);
88d8f9d2afSIgor Opaniuk 
89d8f9d2afSIgor Opaniuk   original_value = *value;
90d8f9d2afSIgor Opaniuk 
91d8f9d2afSIgor Opaniuk   *value += value_to_add;
92d8f9d2afSIgor Opaniuk   if (*value < original_value) {
93d8f9d2afSIgor Opaniuk     avb_error("Overflow when adding values.\n");
94d8f9d2afSIgor Opaniuk     return false;
95d8f9d2afSIgor Opaniuk   }
96d8f9d2afSIgor Opaniuk 
97d8f9d2afSIgor Opaniuk   return true;
98d8f9d2afSIgor Opaniuk }
99d8f9d2afSIgor Opaniuk 
avb_safe_add(uint64_t * out_result,uint64_t a,uint64_t b)100d8f9d2afSIgor Opaniuk bool avb_safe_add(uint64_t* out_result, uint64_t a, uint64_t b) {
101d8f9d2afSIgor Opaniuk   uint64_t dummy;
102d8f9d2afSIgor Opaniuk   if (out_result == NULL) {
103d8f9d2afSIgor Opaniuk     out_result = &dummy;
104d8f9d2afSIgor Opaniuk   }
105d8f9d2afSIgor Opaniuk   *out_result = a;
106d8f9d2afSIgor Opaniuk   return avb_safe_add_to(out_result, b);
107d8f9d2afSIgor Opaniuk }
108d8f9d2afSIgor Opaniuk 
avb_validate_utf8(const uint8_t * data,size_t num_bytes)109d8f9d2afSIgor Opaniuk bool avb_validate_utf8(const uint8_t* data, size_t num_bytes) {
110d8f9d2afSIgor Opaniuk   size_t n;
111d8f9d2afSIgor Opaniuk   unsigned int num_cc;
112d8f9d2afSIgor Opaniuk 
113d8f9d2afSIgor Opaniuk   for (n = 0, num_cc = 0; n < num_bytes; n++) {
114d8f9d2afSIgor Opaniuk     uint8_t c = data[n];
115d8f9d2afSIgor Opaniuk 
116d8f9d2afSIgor Opaniuk     if (num_cc > 0) {
117d8f9d2afSIgor Opaniuk       if ((c & (0x80 | 0x40)) == 0x80) {
118d8f9d2afSIgor Opaniuk         /* 10xx xxxx */
119d8f9d2afSIgor Opaniuk       } else {
120d8f9d2afSIgor Opaniuk         goto fail;
121d8f9d2afSIgor Opaniuk       }
122d8f9d2afSIgor Opaniuk       num_cc--;
123d8f9d2afSIgor Opaniuk     } else {
124d8f9d2afSIgor Opaniuk       if (c < 0x80) {
125d8f9d2afSIgor Opaniuk         num_cc = 0;
126d8f9d2afSIgor Opaniuk       } else if ((c & (0x80 | 0x40 | 0x20)) == (0x80 | 0x40)) {
127d8f9d2afSIgor Opaniuk         /* 110x xxxx */
128d8f9d2afSIgor Opaniuk         num_cc = 1;
129d8f9d2afSIgor Opaniuk       } else if ((c & (0x80 | 0x40 | 0x20 | 0x10)) == (0x80 | 0x40 | 0x20)) {
130d8f9d2afSIgor Opaniuk         /* 1110 xxxx */
131d8f9d2afSIgor Opaniuk         num_cc = 2;
132d8f9d2afSIgor Opaniuk       } else if ((c & (0x80 | 0x40 | 0x20 | 0x10 | 0x08)) ==
133d8f9d2afSIgor Opaniuk                  (0x80 | 0x40 | 0x20 | 0x10)) {
134d8f9d2afSIgor Opaniuk         /* 1111 0xxx */
135d8f9d2afSIgor Opaniuk         num_cc = 3;
136d8f9d2afSIgor Opaniuk       } else {
137d8f9d2afSIgor Opaniuk         goto fail;
138d8f9d2afSIgor Opaniuk       }
139d8f9d2afSIgor Opaniuk     }
140d8f9d2afSIgor Opaniuk   }
141d8f9d2afSIgor Opaniuk 
142d8f9d2afSIgor Opaniuk   if (num_cc != 0) {
143d8f9d2afSIgor Opaniuk     goto fail;
144d8f9d2afSIgor Opaniuk   }
145d8f9d2afSIgor Opaniuk 
146d8f9d2afSIgor Opaniuk   return true;
147d8f9d2afSIgor Opaniuk 
148d8f9d2afSIgor Opaniuk fail:
149d8f9d2afSIgor Opaniuk   return false;
150d8f9d2afSIgor Opaniuk }
151d8f9d2afSIgor Opaniuk 
avb_str_concat(char * buf,size_t buf_size,const char * str1,size_t str1_len,const char * str2,size_t str2_len)152d8f9d2afSIgor Opaniuk bool avb_str_concat(char* buf,
153d8f9d2afSIgor Opaniuk                     size_t buf_size,
154d8f9d2afSIgor Opaniuk                     const char* str1,
155d8f9d2afSIgor Opaniuk                     size_t str1_len,
156d8f9d2afSIgor Opaniuk                     const char* str2,
157d8f9d2afSIgor Opaniuk                     size_t str2_len) {
158d8f9d2afSIgor Opaniuk   uint64_t combined_len;
159d8f9d2afSIgor Opaniuk 
160d8f9d2afSIgor Opaniuk   if (!avb_safe_add(&combined_len, str1_len, str2_len)) {
161d8f9d2afSIgor Opaniuk     avb_error("Overflow when adding string sizes.\n");
162d8f9d2afSIgor Opaniuk     return false;
163d8f9d2afSIgor Opaniuk   }
164d8f9d2afSIgor Opaniuk 
165d8f9d2afSIgor Opaniuk   if (combined_len > buf_size - 1) {
166d8f9d2afSIgor Opaniuk     avb_error("Insufficient buffer space.\n");
167d8f9d2afSIgor Opaniuk     return false;
168d8f9d2afSIgor Opaniuk   }
169d8f9d2afSIgor Opaniuk 
170d8f9d2afSIgor Opaniuk   avb_memcpy(buf, str1, str1_len);
171d8f9d2afSIgor Opaniuk   avb_memcpy(buf + str1_len, str2, str2_len);
172d8f9d2afSIgor Opaniuk   buf[combined_len] = '\0';
173d8f9d2afSIgor Opaniuk 
174d8f9d2afSIgor Opaniuk   return true;
175d8f9d2afSIgor Opaniuk }
176d8f9d2afSIgor Opaniuk 
avb_malloc(size_t size)177d8f9d2afSIgor Opaniuk void* avb_malloc(size_t size) {
178d8f9d2afSIgor Opaniuk   void* ret = avb_malloc_(size);
179d8f9d2afSIgor Opaniuk   if (ret == NULL) {
180d8f9d2afSIgor Opaniuk     avb_error("Failed to allocate memory.\n");
181d8f9d2afSIgor Opaniuk     return NULL;
182d8f9d2afSIgor Opaniuk   }
183d8f9d2afSIgor Opaniuk   return ret;
184d8f9d2afSIgor Opaniuk }
185d8f9d2afSIgor Opaniuk 
avb_calloc(size_t size)186d8f9d2afSIgor Opaniuk void* avb_calloc(size_t size) {
187d8f9d2afSIgor Opaniuk   void* ret = avb_malloc(size);
188d8f9d2afSIgor Opaniuk   if (ret == NULL) {
189d8f9d2afSIgor Opaniuk     return NULL;
190d8f9d2afSIgor Opaniuk   }
191d8f9d2afSIgor Opaniuk 
192d8f9d2afSIgor Opaniuk   avb_memset(ret, '\0', size);
193d8f9d2afSIgor Opaniuk   return ret;
194d8f9d2afSIgor Opaniuk }
195d8f9d2afSIgor Opaniuk 
avb_strdup(const char * str)196d8f9d2afSIgor Opaniuk char* avb_strdup(const char* str) {
197d8f9d2afSIgor Opaniuk   size_t len = avb_strlen(str);
198d8f9d2afSIgor Opaniuk   char* ret = avb_malloc(len + 1);
199d8f9d2afSIgor Opaniuk   if (ret == NULL) {
200d8f9d2afSIgor Opaniuk     return NULL;
201d8f9d2afSIgor Opaniuk   }
202d8f9d2afSIgor Opaniuk 
203d8f9d2afSIgor Opaniuk   avb_memcpy(ret, str, len);
204d8f9d2afSIgor Opaniuk   ret[len] = '\0';
205d8f9d2afSIgor Opaniuk 
206d8f9d2afSIgor Opaniuk   return ret;
207d8f9d2afSIgor Opaniuk }
208d8f9d2afSIgor Opaniuk 
avb_strstr(const char * haystack,const char * needle)209d8f9d2afSIgor Opaniuk const char* avb_strstr(const char* haystack, const char* needle) {
210d8f9d2afSIgor Opaniuk   size_t n, m;
211d8f9d2afSIgor Opaniuk 
212d8f9d2afSIgor Opaniuk   /* Look through |haystack| and check if the first character of
213d8f9d2afSIgor Opaniuk    * |needle| matches. If so, check the rest of |needle|.
214d8f9d2afSIgor Opaniuk    */
215d8f9d2afSIgor Opaniuk   for (n = 0; haystack[n] != '\0'; n++) {
216d8f9d2afSIgor Opaniuk     if (haystack[n] != needle[0]) {
217d8f9d2afSIgor Opaniuk       continue;
218d8f9d2afSIgor Opaniuk     }
219d8f9d2afSIgor Opaniuk 
220d8f9d2afSIgor Opaniuk     for (m = 1;; m++) {
221d8f9d2afSIgor Opaniuk       if (needle[m] == '\0') {
222d8f9d2afSIgor Opaniuk         return haystack + n;
223d8f9d2afSIgor Opaniuk       }
224d8f9d2afSIgor Opaniuk 
225d8f9d2afSIgor Opaniuk       if (haystack[n + m] != needle[m]) {
226d8f9d2afSIgor Opaniuk         break;
227d8f9d2afSIgor Opaniuk       }
228d8f9d2afSIgor Opaniuk     }
229d8f9d2afSIgor Opaniuk   }
230d8f9d2afSIgor Opaniuk 
231d8f9d2afSIgor Opaniuk   return NULL;
232d8f9d2afSIgor Opaniuk }
233d8f9d2afSIgor Opaniuk 
avb_strv_find_str(const char * const * strings,const char * str,size_t str_size)234d8f9d2afSIgor Opaniuk const char* avb_strv_find_str(const char* const* strings,
235d8f9d2afSIgor Opaniuk                               const char* str,
236d8f9d2afSIgor Opaniuk                               size_t str_size) {
237d8f9d2afSIgor Opaniuk   size_t n;
238d8f9d2afSIgor Opaniuk   for (n = 0; strings[n] != NULL; n++) {
239d8f9d2afSIgor Opaniuk     if (avb_strlen(strings[n]) == str_size &&
240d8f9d2afSIgor Opaniuk         avb_memcmp(strings[n], str, str_size) == 0) {
241d8f9d2afSIgor Opaniuk       return strings[n];
242d8f9d2afSIgor Opaniuk     }
243d8f9d2afSIgor Opaniuk   }
244d8f9d2afSIgor Opaniuk   return NULL;
245d8f9d2afSIgor Opaniuk }
246d8f9d2afSIgor Opaniuk 
avb_replace(const char * str,const char * search,const char * replace)247d8f9d2afSIgor Opaniuk char* avb_replace(const char* str, const char* search, const char* replace) {
248d8f9d2afSIgor Opaniuk   char* ret = NULL;
249d8f9d2afSIgor Opaniuk   size_t ret_len = 0;
250d8f9d2afSIgor Opaniuk   size_t search_len, replace_len;
251d8f9d2afSIgor Opaniuk   const char* str_after_last_replace;
252d8f9d2afSIgor Opaniuk 
253d8f9d2afSIgor Opaniuk   search_len = avb_strlen(search);
254d8f9d2afSIgor Opaniuk   replace_len = avb_strlen(replace);
255d8f9d2afSIgor Opaniuk 
256d8f9d2afSIgor Opaniuk   str_after_last_replace = str;
257d8f9d2afSIgor Opaniuk   while (*str != '\0') {
258d8f9d2afSIgor Opaniuk     const char* s;
259d8f9d2afSIgor Opaniuk     size_t num_before;
260d8f9d2afSIgor Opaniuk     size_t num_new;
261d8f9d2afSIgor Opaniuk 
262d8f9d2afSIgor Opaniuk     s = avb_strstr(str, search);
263d8f9d2afSIgor Opaniuk     if (s == NULL) {
264d8f9d2afSIgor Opaniuk       break;
265d8f9d2afSIgor Opaniuk     }
266d8f9d2afSIgor Opaniuk 
267d8f9d2afSIgor Opaniuk     num_before = s - str;
268d8f9d2afSIgor Opaniuk 
269d8f9d2afSIgor Opaniuk     if (ret == NULL) {
270d8f9d2afSIgor Opaniuk       num_new = num_before + replace_len + 1;
271d8f9d2afSIgor Opaniuk       ret = avb_malloc(num_new);
272d8f9d2afSIgor Opaniuk       if (ret == NULL) {
273d8f9d2afSIgor Opaniuk         goto out;
274d8f9d2afSIgor Opaniuk       }
275d8f9d2afSIgor Opaniuk       avb_memcpy(ret, str, num_before);
276d8f9d2afSIgor Opaniuk       avb_memcpy(ret + num_before, replace, replace_len);
277d8f9d2afSIgor Opaniuk       ret[num_new - 1] = '\0';
278d8f9d2afSIgor Opaniuk       ret_len = num_new - 1;
279d8f9d2afSIgor Opaniuk     } else {
280d8f9d2afSIgor Opaniuk       char* new_str;
281d8f9d2afSIgor Opaniuk       num_new = ret_len + num_before + replace_len + 1;
282d8f9d2afSIgor Opaniuk       new_str = avb_malloc(num_new);
283d8f9d2afSIgor Opaniuk       if (new_str == NULL) {
284d8f9d2afSIgor Opaniuk         goto out;
285d8f9d2afSIgor Opaniuk       }
286d8f9d2afSIgor Opaniuk       avb_memcpy(new_str, ret, ret_len);
287d8f9d2afSIgor Opaniuk       avb_memcpy(new_str + ret_len, str, num_before);
288d8f9d2afSIgor Opaniuk       avb_memcpy(new_str + ret_len + num_before, replace, replace_len);
289d8f9d2afSIgor Opaniuk       new_str[num_new - 1] = '\0';
290d8f9d2afSIgor Opaniuk       avb_free(ret);
291d8f9d2afSIgor Opaniuk       ret = new_str;
292d8f9d2afSIgor Opaniuk       ret_len = num_new - 1;
293d8f9d2afSIgor Opaniuk     }
294d8f9d2afSIgor Opaniuk 
295d8f9d2afSIgor Opaniuk     str = s + search_len;
296d8f9d2afSIgor Opaniuk     str_after_last_replace = str;
297d8f9d2afSIgor Opaniuk   }
298d8f9d2afSIgor Opaniuk 
299d8f9d2afSIgor Opaniuk   if (ret == NULL) {
300d8f9d2afSIgor Opaniuk     ret = avb_strdup(str_after_last_replace);
301d8f9d2afSIgor Opaniuk     if (ret == NULL) {
302d8f9d2afSIgor Opaniuk       goto out;
303d8f9d2afSIgor Opaniuk     }
304d8f9d2afSIgor Opaniuk   } else {
305d8f9d2afSIgor Opaniuk     size_t num_remaining = avb_strlen(str_after_last_replace);
306d8f9d2afSIgor Opaniuk     size_t num_new = ret_len + num_remaining + 1;
307d8f9d2afSIgor Opaniuk     char* new_str = avb_malloc(num_new);
308d8f9d2afSIgor Opaniuk     if (new_str == NULL) {
309d8f9d2afSIgor Opaniuk       goto out;
310d8f9d2afSIgor Opaniuk     }
311d8f9d2afSIgor Opaniuk     avb_memcpy(new_str, ret, ret_len);
312d8f9d2afSIgor Opaniuk     avb_memcpy(new_str + ret_len, str_after_last_replace, num_remaining);
313d8f9d2afSIgor Opaniuk     new_str[num_new - 1] = '\0';
314d8f9d2afSIgor Opaniuk     avb_free(ret);
315d8f9d2afSIgor Opaniuk     ret = new_str;
316d8f9d2afSIgor Opaniuk     ret_len = num_new - 1;
317d8f9d2afSIgor Opaniuk   }
318d8f9d2afSIgor Opaniuk 
319d8f9d2afSIgor Opaniuk out:
320d8f9d2afSIgor Opaniuk   return ret;
321d8f9d2afSIgor Opaniuk }
322d8f9d2afSIgor Opaniuk 
323d8f9d2afSIgor Opaniuk /* We only support a limited amount of strings in avb_strdupv(). */
324d8f9d2afSIgor Opaniuk #define AVB_STRDUPV_MAX_NUM_STRINGS 32
325d8f9d2afSIgor Opaniuk 
avb_strdupv(const char * str,...)326d8f9d2afSIgor Opaniuk char* avb_strdupv(const char* str, ...) {
327d8f9d2afSIgor Opaniuk   va_list ap;
328d8f9d2afSIgor Opaniuk   const char* strings[AVB_STRDUPV_MAX_NUM_STRINGS];
329d8f9d2afSIgor Opaniuk   size_t lengths[AVB_STRDUPV_MAX_NUM_STRINGS];
330d8f9d2afSIgor Opaniuk   size_t num_strings, n;
331d8f9d2afSIgor Opaniuk   uint64_t total_length;
332d8f9d2afSIgor Opaniuk   char *ret = NULL, *dest;
333d8f9d2afSIgor Opaniuk 
334d8f9d2afSIgor Opaniuk   num_strings = 0;
335d8f9d2afSIgor Opaniuk   total_length = 0;
336d8f9d2afSIgor Opaniuk   va_start(ap, str);
337d8f9d2afSIgor Opaniuk   do {
338d8f9d2afSIgor Opaniuk     size_t str_len = avb_strlen(str);
339d8f9d2afSIgor Opaniuk     strings[num_strings] = str;
340d8f9d2afSIgor Opaniuk     lengths[num_strings] = str_len;
341d8f9d2afSIgor Opaniuk     if (!avb_safe_add_to(&total_length, str_len)) {
342d8f9d2afSIgor Opaniuk       avb_fatal("Overflow while determining total length.\n");
343d8f9d2afSIgor Opaniuk       break;
344d8f9d2afSIgor Opaniuk     }
345d8f9d2afSIgor Opaniuk     num_strings++;
346d8f9d2afSIgor Opaniuk     if (num_strings == AVB_STRDUPV_MAX_NUM_STRINGS) {
347d8f9d2afSIgor Opaniuk       avb_fatal("Too many strings passed.\n");
348d8f9d2afSIgor Opaniuk       break;
349d8f9d2afSIgor Opaniuk     }
350d8f9d2afSIgor Opaniuk     str = va_arg(ap, const char*);
351d8f9d2afSIgor Opaniuk   } while (str != NULL);
352d8f9d2afSIgor Opaniuk   va_end(ap);
353d8f9d2afSIgor Opaniuk 
354d8f9d2afSIgor Opaniuk   ret = avb_malloc(total_length + 1);
355d8f9d2afSIgor Opaniuk   if (ret == NULL) {
356d8f9d2afSIgor Opaniuk     goto out;
357d8f9d2afSIgor Opaniuk   }
358d8f9d2afSIgor Opaniuk 
359d8f9d2afSIgor Opaniuk   dest = ret;
360d8f9d2afSIgor Opaniuk   for (n = 0; n < num_strings; n++) {
361d8f9d2afSIgor Opaniuk     avb_memcpy(dest, strings[n], lengths[n]);
362d8f9d2afSIgor Opaniuk     dest += lengths[n];
363d8f9d2afSIgor Opaniuk   }
364d8f9d2afSIgor Opaniuk   *dest = '\0';
365d8f9d2afSIgor Opaniuk   avb_assert(dest == ret + total_length);
366d8f9d2afSIgor Opaniuk 
367d8f9d2afSIgor Opaniuk out:
368d8f9d2afSIgor Opaniuk   return ret;
369d8f9d2afSIgor Opaniuk }
370d8f9d2afSIgor Opaniuk 
avb_basename(const char * str)371d8f9d2afSIgor Opaniuk const char* avb_basename(const char* str) {
372d8f9d2afSIgor Opaniuk   int64_t n;
373d8f9d2afSIgor Opaniuk   size_t len;
374d8f9d2afSIgor Opaniuk 
375d8f9d2afSIgor Opaniuk   len = avb_strlen(str);
376d8f9d2afSIgor Opaniuk   if (len >= 2) {
377d8f9d2afSIgor Opaniuk     for (n = len - 2; n >= 0; n--) {
378d8f9d2afSIgor Opaniuk       if (str[n] == '/') {
379d8f9d2afSIgor Opaniuk         return str + n + 1;
380d8f9d2afSIgor Opaniuk       }
381d8f9d2afSIgor Opaniuk     }
382d8f9d2afSIgor Opaniuk   }
383d8f9d2afSIgor Opaniuk   return str;
384d8f9d2afSIgor Opaniuk }
385d8f9d2afSIgor Opaniuk 
avb_uppercase(char * str)386d8f9d2afSIgor Opaniuk void avb_uppercase(char* str) {
387d8f9d2afSIgor Opaniuk   size_t i;
388d8f9d2afSIgor Opaniuk   for (i = 0; str[i] != '\0'; ++i) {
389d8f9d2afSIgor Opaniuk     if (str[i] <= 0x7A && str[i] >= 0x61) {
390d8f9d2afSIgor Opaniuk       str[i] -= 0x20;
391d8f9d2afSIgor Opaniuk     }
392d8f9d2afSIgor Opaniuk   }
393d8f9d2afSIgor Opaniuk }
394d8f9d2afSIgor Opaniuk 
avb_bin2hex(const uint8_t * data,size_t data_len)395d8f9d2afSIgor Opaniuk char* avb_bin2hex(const uint8_t* data, size_t data_len) {
396d8f9d2afSIgor Opaniuk   const char hex_digits[17] = "0123456789abcdef";
397d8f9d2afSIgor Opaniuk   char* hex_data;
398d8f9d2afSIgor Opaniuk   size_t n;
399d8f9d2afSIgor Opaniuk 
400d8f9d2afSIgor Opaniuk   hex_data = avb_malloc(data_len * 2 + 1);
401d8f9d2afSIgor Opaniuk   if (hex_data == NULL) {
402d8f9d2afSIgor Opaniuk     return NULL;
403d8f9d2afSIgor Opaniuk   }
404d8f9d2afSIgor Opaniuk 
405d8f9d2afSIgor Opaniuk   for (n = 0; n < data_len; n++) {
406d8f9d2afSIgor Opaniuk     hex_data[n * 2] = hex_digits[data[n] >> 4];
407d8f9d2afSIgor Opaniuk     hex_data[n * 2 + 1] = hex_digits[data[n] & 0x0f];
408d8f9d2afSIgor Opaniuk   }
409d8f9d2afSIgor Opaniuk   hex_data[n * 2] = '\0';
410d8f9d2afSIgor Opaniuk   return hex_data;
411d8f9d2afSIgor Opaniuk }
412