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