diff --git a/formats/m3u/m3u_file.c b/formats/m3u/m3u_file.c index 142a226..00a3c73 100644 --- a/formats/m3u/m3u_file.c +++ b/formats/m3u/m3u_file.c @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -50,8 +51,6 @@ struct content_m3u_file { char *path; - size_t size; - size_t capacity; m3u_file_entry_t *entries; }; @@ -66,6 +65,7 @@ static bool m3u_file_load(m3u_file_t *m3u_file) int64_t file_len = 0; uint8_t *file_buf = NULL; struct string_list *lines = NULL; + bool success = false; size_t i; char entry_path[PATH_MAX_LENGTH]; char entry_label[PATH_MAX_LENGTH]; @@ -74,27 +74,28 @@ static bool m3u_file_load(m3u_file_t *m3u_file) entry_label[0] = '\0'; if (!m3u_file) - return false; + goto end; /* Check whether file exists * > If path is empty, then an error * has occurred... */ if (string_is_empty(m3u_file->path)) - return false; + goto end; /* > File must have the correct extension */ file_ext = path_get_extension(m3u_file->path); - if (string_is_empty(file_ext)) - return false; - - if (!string_is_equal_noncase(file_ext, M3U_FILE_EXT)) - return false; + if (string_is_empty(file_ext) || + !string_is_equal_noncase(file_ext, M3U_FILE_EXT)) + goto end; /* > If file does not exist, no action * is required */ if (!path_is_valid(m3u_file->path)) - return true; + { + success = true; + goto end; + } /* Read file from disk */ if (filestream_read_file(m3u_file->path, (void**)&file_buf, &file_len) >= 0) @@ -105,52 +106,50 @@ static bool m3u_file_load(m3u_file_t *m3u_file) /* File buffer no longer required */ if (file_buf) + { free(file_buf); + file_buf = NULL; + } } + /* File IO error... */ else - { - /* File IO error... */ - if (file_buf) - free(file_buf); - return false; - } + goto end; /* If file was empty, no action is required */ if (!lines) - return true; + { + success = true; + goto end; + } /* Parse lines of file */ for (i = 0; i < lines->size; i++) { - size_t m3u_size; const char *line = lines->elems[i].data; if (string_is_empty(line)) continue; /* Determine line 'type' */ - m3u_size = STRLEN_CONST(M3U_FILE_NONSTD_LABEL); /* > '#LABEL:' */ - if (!strncmp( - line, M3U_FILE_NONSTD_LABEL, - m3u_size)) + if (string_starts_with_size(line, M3U_FILE_NONSTD_LABEL, + STRLEN_CONST(M3U_FILE_NONSTD_LABEL))) { /* Label is the string to the right * of '#LABEL:' */ - const char *label = line + m3u_size; + const char *label = line + STRLEN_CONST(M3U_FILE_NONSTD_LABEL); if (!string_is_empty(label)) { strlcpy( - entry_label, line + m3u_size, + entry_label, line + STRLEN_CONST(M3U_FILE_NONSTD_LABEL), sizeof(entry_label)); string_trim_whitespace(entry_label); } } /* > '#EXTINF:' */ - else if (!strncmp( - line, M3U_FILE_EXTSTD_LABEL, + else if (string_starts_with_size(line, M3U_FILE_EXTSTD_LABEL, STRLEN_CONST(M3U_FILE_EXTSTD_LABEL))) { /* Label is the string to the right @@ -210,9 +209,13 @@ static bool m3u_file_load(m3u_file_t *m3u_file) } /* Add entry to file - * > Ignore errors here - invalid entries - * will just be omitted */ - m3u_file_add_entry(m3u_file, entry_path, entry_label); + * > Note: The only way that m3u_file_add_entry() + * can fail here is if we run out of memory. + * This is a critical error, and m3u_file must + * be considered invalid in this case */ + if (!string_is_empty(entry_path) && + !m3u_file_add_entry(m3u_file, entry_path, entry_label)) + goto end; /* Reset entry_path/entry_label */ entry_path[0] = '\0'; @@ -220,6 +223,9 @@ static bool m3u_file_load(m3u_file_t *m3u_file) } } + success = true; + +end: /* Clean up */ if (lines) { @@ -227,7 +233,13 @@ static bool m3u_file_load(m3u_file_t *m3u_file) lines = NULL; } - return true; + if (file_buf) + { + free(file_buf); + file_buf = NULL; + } + + return success; } /* Creates and initialises an M3U file @@ -238,16 +250,15 @@ static bool m3u_file_load(m3u_file_t *m3u_file) * - Returned m3u_file_t object must be free'd using * m3u_file_free() * - Returns NULL in the event of an error */ -m3u_file_t *m3u_file_init(const char *path, size_t size) +m3u_file_t *m3u_file_init(const char *path) { - m3u_file_entry_t *entries = NULL; - m3u_file_t *m3u_file = NULL; + m3u_file_t *m3u_file = NULL; char m3u_path[PATH_MAX_LENGTH]; m3u_path[0] = '\0'; /* Sanity check */ - if (string_is_empty(path) || (size < 1)) + if (string_is_empty(path)) return NULL; /* Get 'real' file path */ @@ -258,27 +269,17 @@ m3u_file_t *m3u_file_init(const char *path, size_t size) return NULL; /* Create m3u_file_t object */ - m3u_file = (m3u_file_t*)calloc(1, sizeof(*m3u_file)); + m3u_file = (m3u_file_t*)malloc(sizeof(*m3u_file)); if (!m3u_file) return NULL; - /* Create m3u_file_entry_t array */ - entries = (m3u_file_entry_t*)calloc(size, sizeof(*entries)); - - if (!entries) - { - free(m3u_file); - return NULL; - } + /* Initialise members */ + m3u_file->path = NULL; + m3u_file->entries = NULL; /* Copy file path */ - m3u_file->path = strdup(m3u_path); - - /* Set remaining values */ - m3u_file->size = 0; - m3u_file->capacity = size; - m3u_file->entries = entries; + m3u_file->path = strdup(m3u_path); /* Read existing file contents from * disk, if required */ @@ -327,15 +328,14 @@ void m3u_file_free(m3u_file_t *m3u_file) /* Free entries */ if (m3u_file->entries) { - for (i = 0; i < m3u_file->size; i++) + for (i = 0; i < RBUF_LEN(m3u_file->entries); i++) { m3u_file_entry_t *entry = &m3u_file->entries[i]; m3u_file_free_entry(entry); } - free(m3u_file->entries); + RBUF_FREE(m3u_file->entries); } - m3u_file->entries = NULL; free(m3u_file); } @@ -357,17 +357,7 @@ size_t m3u_file_get_size(m3u_file_t *m3u_file) if (!m3u_file) return 0; - return m3u_file->size; -} - -/* Returns maximum number of entries permitted - * in M3U file */ -size_t m3u_file_get_capacity(m3u_file_t *m3u_file) -{ - if (!m3u_file) - return 0; - - return m3u_file->capacity; + return RBUF_LEN(m3u_file->entries); } /* Fetches specified M3U file entry @@ -378,8 +368,7 @@ bool m3u_file_get_entry( { if (!m3u_file || !entry || - (idx >= m3u_file->size) || - !m3u_file->entries) + (idx >= RBUF_LEN(m3u_file->entries))) return false; *entry = &m3u_file->entries[idx]; @@ -393,30 +382,35 @@ bool m3u_file_get_entry( /* Setters */ /* Adds specified entry to the M3U file - * - Returns false if path is invalid, or M3U - * file capacity is exceeded */ + * - Returns false if path is invalid, or + * memory could not be allocated for the + * entry */ bool m3u_file_add_entry( m3u_file_t *m3u_file, const char *path, const char *label) { m3u_file_entry_t *entry = NULL; + size_t num_entries; char full_path[PATH_MAX_LENGTH]; full_path[0] = '\0'; - if (!m3u_file || - !m3u_file->entries || - (m3u_file->size >= m3u_file->capacity) || - string_is_empty(path)) + if (!m3u_file || string_is_empty(path)) return false; - /* Get new entry at end of list */ - entry = &m3u_file->entries[m3u_file->size]; + /* Get current number of file entries */ + num_entries = RBUF_LEN(m3u_file->entries); - if (!entry) + /* Attempt to allocate memory for new entry */ + if (!RBUF_TRYFIT(m3u_file->entries, num_entries + 1)) return false; - /* Ensure entry is free'd */ - m3u_file_free_entry(entry); + /* Allocation successful - increment array size */ + RBUF_RESIZE(m3u_file->entries, num_entries + 1); + + /* Fetch entry at end of list, and zero-initialise + * members */ + entry = &m3u_file->entries[num_entries]; + memset(entry, 0, sizeof(*entry)); /* Copy path and label */ entry->path = strdup(path); @@ -444,9 +438,6 @@ bool m3u_file_add_entry( entry->full_path = strdup(full_path); - /* Increment size counter */ - m3u_file->size++; - return true; } @@ -460,14 +451,14 @@ void m3u_file_clear(m3u_file_t *m3u_file) if (m3u_file->entries) { - for (i = 0; i < m3u_file->size; i++) + for (i = 0; i < RBUF_LEN(m3u_file->entries); i++) { m3u_file_entry_t *entry = &m3u_file->entries[i]; m3u_file_free_entry(entry); } - } - m3u_file->size = 0; + RBUF_FREE(m3u_file->entries); + } } /* Saving */ @@ -510,7 +501,7 @@ bool m3u_file_save( return false; /* Loop over entries */ - for (i = 0; i < m3u_file->size; i++) + for (i = 0; i < RBUF_LEN(m3u_file->entries); i++) { m3u_file_entry_t *entry = &m3u_file->entries[i]; char entry_path[PATH_MAX_LENGTH]; @@ -593,13 +584,18 @@ static int m3u_file_qsort_func( /* Sorts M3U file entries in alphabetical order */ void m3u_file_qsort(m3u_file_t *m3u_file) { - if (!m3u_file || - !m3u_file->entries || - (m3u_file->size < 2)) + size_t num_entries; + + if (!m3u_file) + return; + + num_entries = RBUF_LEN(m3u_file->entries); + + if (num_entries < 2) return; qsort( - m3u_file->entries, m3u_file->size, + m3u_file->entries, num_entries, sizeof(m3u_file_entry_t), (int (*)(const void *, const void *))m3u_file_qsort_func); } diff --git a/include/array/rbuf.h b/include/array/rbuf.h index 388542b..3ec1538 100644 --- a/include/array/rbuf.h +++ b/include/array/rbuf.h @@ -33,6 +33,9 @@ * The first time an element is added, memory for 16 elements are allocated. * Then every time length is about to exceed capacity, capacity is doubled. * + * Be careful not to supply modifying statements to the macro arguments. + * Something like RBUF_REMOVE(buf, i--); would have unintended results. + * * Sample usage: * * mytype_t* buf = NULL; @@ -74,6 +77,7 @@ #define RBUF_RESIZE(b, sz) (RBUF_FIT((b), (sz)), ((b) ? RBUF__HDR(b)->len = (sz) : 0)) #define RBUF_CLEAR(b) ((b) ? RBUF__HDR(b)->len = 0 : 0) #define RBUF_TRYFIT(b, n) (RBUF_FIT((b), (n)), (((b) && RBUF_CAP(b) >= (size_t)(n)) || !(n))) +#define RBUF_REMOVE(b, idx) memmove((b) + (idx), (b) + (idx) + 1, (--RBUF__HDR(b)->len - (idx)) * sizeof(*(b))) struct rbuf__hdr { diff --git a/include/formats/m3u_file.h b/include/formats/m3u_file.h index 7fa8c03..83a1625 100644 --- a/include/formats/m3u_file.h +++ b/include/formats/m3u_file.h @@ -36,9 +36,6 @@ RETRO_BEGIN_DECLS /* M3U file extension */ #define M3U_FILE_EXT "m3u" -/* Default maximum number of M3U entries */ -#define M3U_FILE_SIZE 2048 - /* Prevent direct access to m3u_file_t members */ typedef struct content_m3u_file m3u_file_t; @@ -70,7 +67,7 @@ enum m3u_file_label_type * - Returned m3u_file_t object must be free'd using * m3u_file_free() * - Returns NULL in the event of an error */ -m3u_file_t *m3u_file_init(const char *path, size_t size); +m3u_file_t *m3u_file_init(const char *path); /* Frees specified M3U file */ void m3u_file_free(m3u_file_t *m3u_file); @@ -83,10 +80,6 @@ char *m3u_file_get_path(m3u_file_t *m3u_file); /* Returns number of entries in M3U file */ size_t m3u_file_get_size(m3u_file_t *m3u_file); -/* Returns maximum number of entries permitted - * in M3U file */ -size_t m3u_file_get_capacity(m3u_file_t *m3u_file); - /* Fetches specified M3U file entry * - Returns false if 'idx' is invalid, or internal * entry is NULL */ @@ -96,8 +89,9 @@ bool m3u_file_get_entry( /* Setters */ /* Adds specified entry to the M3U file - * - Returns false if path is invalid, or M3U - * file capacity is exceeded */ + * - Returns false if path is invalid, or + * memory could not be allocated for the + * entry */ bool m3u_file_add_entry( m3u_file_t *m3u_file, const char *path, const char *label); diff --git a/include/libretro.h b/include/libretro.h index 1ae508f..c8a3cb7 100644 --- a/include/libretro.h +++ b/include/libretro.h @@ -1321,6 +1321,20 @@ enum retro_mod * fallback, stderr). */ +#define RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS 61 + /* unsigned * -- + * Unsigned value is the number of active input devices + * provided by the frontend. This may change between + * frames, but will remain constant for the duration + * of each frame. + * If callback returns true, a core need not poll any + * input device with an index greater than or equal to + * the number of active devices. + * If callback returns false, the number of active input + * devices is unknown. In this case, all input devices + * should be considered active. + */ + /* VFS functionality */ /* File paths: