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*)∈ 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*)∈ 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