(m3u_file) Replace static entries array with dynamic array via RBUF library

This commit is contained in:
jdgleaver 2020-08-13 17:24:00 +01:00
parent b972327bc6
commit b19eb64329
4 changed files with 89 additions and 99 deletions

View File

@ -26,6 +26,7 @@
#include <lists/string_list.h> #include <lists/string_list.h>
#include <file/file_path.h> #include <file/file_path.h>
#include <streams/file_stream.h> #include <streams/file_stream.h>
#include <array/rbuf.h>
#include <formats/m3u_file.h> #include <formats/m3u_file.h>
@ -50,8 +51,6 @@
struct content_m3u_file struct content_m3u_file
{ {
char *path; char *path;
size_t size;
size_t capacity;
m3u_file_entry_t *entries; m3u_file_entry_t *entries;
}; };
@ -66,6 +65,7 @@ static bool m3u_file_load(m3u_file_t *m3u_file)
int64_t file_len = 0; int64_t file_len = 0;
uint8_t *file_buf = NULL; uint8_t *file_buf = NULL;
struct string_list *lines = NULL; struct string_list *lines = NULL;
bool success = false;
size_t i; size_t i;
char entry_path[PATH_MAX_LENGTH]; char entry_path[PATH_MAX_LENGTH];
char entry_label[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'; entry_label[0] = '\0';
if (!m3u_file) if (!m3u_file)
return false; goto end;
/* Check whether file exists /* Check whether file exists
* > If path is empty, then an error * > If path is empty, then an error
* has occurred... */ * has occurred... */
if (string_is_empty(m3u_file->path)) if (string_is_empty(m3u_file->path))
return false; goto end;
/* > File must have the correct extension */ /* > File must have the correct extension */
file_ext = path_get_extension(m3u_file->path); file_ext = path_get_extension(m3u_file->path);
if (string_is_empty(file_ext)) if (string_is_empty(file_ext) ||
return false; !string_is_equal_noncase(file_ext, M3U_FILE_EXT))
goto end;
if (!string_is_equal_noncase(file_ext, M3U_FILE_EXT))
return false;
/* > If file does not exist, no action /* > If file does not exist, no action
* is required */ * is required */
if (!path_is_valid(m3u_file->path)) if (!path_is_valid(m3u_file->path))
return true; {
success = true;
goto end;
}
/* Read file from disk */ /* Read file from disk */
if (filestream_read_file(m3u_file->path, (void**)&file_buf, &file_len) >= 0) 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 */ /* File buffer no longer required */
if (file_buf) if (file_buf)
{
free(file_buf); free(file_buf);
file_buf = NULL;
}
} }
/* File IO error... */
else else
{ goto end;
/* File IO error... */
if (file_buf)
free(file_buf);
return false;
}
/* If file was empty, no action is required */ /* If file was empty, no action is required */
if (!lines) if (!lines)
return true; {
success = true;
goto end;
}
/* Parse lines of file */ /* Parse lines of file */
for (i = 0; i < lines->size; i++) for (i = 0; i < lines->size; i++)
{ {
size_t m3u_size;
const char *line = lines->elems[i].data; const char *line = lines->elems[i].data;
if (string_is_empty(line)) if (string_is_empty(line))
continue; continue;
/* Determine line 'type' */ /* Determine line 'type' */
m3u_size = STRLEN_CONST(M3U_FILE_NONSTD_LABEL);
/* > '#LABEL:' */ /* > '#LABEL:' */
if (!strncmp( if (string_starts_with_size(line, M3U_FILE_NONSTD_LABEL,
line, M3U_FILE_NONSTD_LABEL, STRLEN_CONST(M3U_FILE_NONSTD_LABEL)))
m3u_size))
{ {
/* Label is the string to the right /* Label is the string to the right
* of '#LABEL:' */ * of '#LABEL:' */
const char *label = line + m3u_size; const char *label = line + STRLEN_CONST(M3U_FILE_NONSTD_LABEL);
if (!string_is_empty(label)) if (!string_is_empty(label))
{ {
strlcpy( strlcpy(
entry_label, line + m3u_size, entry_label, line + STRLEN_CONST(M3U_FILE_NONSTD_LABEL),
sizeof(entry_label)); sizeof(entry_label));
string_trim_whitespace(entry_label); string_trim_whitespace(entry_label);
} }
} }
/* > '#EXTINF:' */ /* > '#EXTINF:' */
else if (!strncmp( else if (string_starts_with_size(line, M3U_FILE_EXTSTD_LABEL,
line, M3U_FILE_EXTSTD_LABEL,
STRLEN_CONST(M3U_FILE_EXTSTD_LABEL))) STRLEN_CONST(M3U_FILE_EXTSTD_LABEL)))
{ {
/* Label is the string to the right /* 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 /* Add entry to file
* > Ignore errors here - invalid entries * > Note: The only way that m3u_file_add_entry()
* will just be omitted */ * can fail here is if we run out of memory.
m3u_file_add_entry(m3u_file, entry_path, entry_label); * 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 */ /* Reset entry_path/entry_label */
entry_path[0] = '\0'; entry_path[0] = '\0';
@ -220,6 +223,9 @@ static bool m3u_file_load(m3u_file_t *m3u_file)
} }
} }
success = true;
end:
/* Clean up */ /* Clean up */
if (lines) if (lines)
{ {
@ -227,7 +233,13 @@ static bool m3u_file_load(m3u_file_t *m3u_file)
lines = NULL; lines = NULL;
} }
return true; if (file_buf)
{
free(file_buf);
file_buf = NULL;
}
return success;
} }
/* Creates and initialises an M3U file /* 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 * - Returned m3u_file_t object must be free'd using
* m3u_file_free() * m3u_file_free()
* - Returns NULL in the event of an error */ * - 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]; char m3u_path[PATH_MAX_LENGTH];
m3u_path[0] = '\0'; m3u_path[0] = '\0';
/* Sanity check */ /* Sanity check */
if (string_is_empty(path) || (size < 1)) if (string_is_empty(path))
return NULL; return NULL;
/* Get 'real' file path */ /* Get 'real' file path */
@ -258,27 +269,17 @@ m3u_file_t *m3u_file_init(const char *path, size_t size)
return NULL; return NULL;
/* Create m3u_file_t object */ /* 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) if (!m3u_file)
return NULL; return NULL;
/* Create m3u_file_entry_t array */ /* Initialise members */
entries = (m3u_file_entry_t*)calloc(size, sizeof(*entries)); m3u_file->path = NULL;
m3u_file->entries = NULL;
if (!entries)
{
free(m3u_file);
return NULL;
}
/* Copy file path */ /* Copy file path */
m3u_file->path = strdup(m3u_path); m3u_file->path = strdup(m3u_path);
/* Set remaining values */
m3u_file->size = 0;
m3u_file->capacity = size;
m3u_file->entries = entries;
/* Read existing file contents from /* Read existing file contents from
* disk, if required */ * disk, if required */
@ -327,15 +328,14 @@ void m3u_file_free(m3u_file_t *m3u_file)
/* Free entries */ /* Free entries */
if (m3u_file->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_entry_t *entry = &m3u_file->entries[i];
m3u_file_free_entry(entry); m3u_file_free_entry(entry);
} }
free(m3u_file->entries); RBUF_FREE(m3u_file->entries);
} }
m3u_file->entries = NULL;
free(m3u_file); free(m3u_file);
} }
@ -357,17 +357,7 @@ size_t m3u_file_get_size(m3u_file_t *m3u_file)
if (!m3u_file) if (!m3u_file)
return 0; return 0;
return m3u_file->size; return RBUF_LEN(m3u_file->entries);
}
/* 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;
} }
/* Fetches specified M3U file entry /* Fetches specified M3U file entry
@ -378,8 +368,7 @@ bool m3u_file_get_entry(
{ {
if (!m3u_file || if (!m3u_file ||
!entry || !entry ||
(idx >= m3u_file->size) || (idx >= RBUF_LEN(m3u_file->entries)))
!m3u_file->entries)
return false; return false;
*entry = &m3u_file->entries[idx]; *entry = &m3u_file->entries[idx];
@ -393,30 +382,35 @@ bool m3u_file_get_entry(
/* Setters */ /* Setters */
/* Adds specified entry to the M3U file /* Adds specified entry to the M3U file
* - Returns false if path is invalid, or M3U * - Returns false if path is invalid, or
* file capacity is exceeded */ * memory could not be allocated for the
* entry */
bool m3u_file_add_entry( bool m3u_file_add_entry(
m3u_file_t *m3u_file, const char *path, const char *label) m3u_file_t *m3u_file, const char *path, const char *label)
{ {
m3u_file_entry_t *entry = NULL; m3u_file_entry_t *entry = NULL;
size_t num_entries;
char full_path[PATH_MAX_LENGTH]; char full_path[PATH_MAX_LENGTH];
full_path[0] = '\0'; full_path[0] = '\0';
if (!m3u_file || if (!m3u_file || string_is_empty(path))
!m3u_file->entries ||
(m3u_file->size >= m3u_file->capacity) ||
string_is_empty(path))
return false; return false;
/* Get new entry at end of list */ /* Get current number of file entries */
entry = &m3u_file->entries[m3u_file->size]; 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; return false;
/* Ensure entry is free'd */ /* Allocation successful - increment array size */
m3u_file_free_entry(entry); 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 */ /* Copy path and label */
entry->path = strdup(path); entry->path = strdup(path);
@ -444,9 +438,6 @@ bool m3u_file_add_entry(
entry->full_path = strdup(full_path); entry->full_path = strdup(full_path);
/* Increment size counter */
m3u_file->size++;
return true; return true;
} }
@ -460,14 +451,14 @@ void m3u_file_clear(m3u_file_t *m3u_file)
if (m3u_file->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_entry_t *entry = &m3u_file->entries[i];
m3u_file_free_entry(entry); m3u_file_free_entry(entry);
} }
}
m3u_file->size = 0; RBUF_FREE(m3u_file->entries);
}
} }
/* Saving */ /* Saving */
@ -510,7 +501,7 @@ bool m3u_file_save(
return false; return false;
/* Loop over entries */ /* 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]; m3u_file_entry_t *entry = &m3u_file->entries[i];
char entry_path[PATH_MAX_LENGTH]; char entry_path[PATH_MAX_LENGTH];
@ -593,13 +584,18 @@ static int m3u_file_qsort_func(
/* Sorts M3U file entries in alphabetical order */ /* Sorts M3U file entries in alphabetical order */
void m3u_file_qsort(m3u_file_t *m3u_file) void m3u_file_qsort(m3u_file_t *m3u_file)
{ {
if (!m3u_file || size_t num_entries;
!m3u_file->entries ||
(m3u_file->size < 2)) if (!m3u_file)
return;
num_entries = RBUF_LEN(m3u_file->entries);
if (num_entries < 2)
return; return;
qsort( qsort(
m3u_file->entries, m3u_file->size, m3u_file->entries, num_entries,
sizeof(m3u_file_entry_t), sizeof(m3u_file_entry_t),
(int (*)(const void *, const void *))m3u_file_qsort_func); (int (*)(const void *, const void *))m3u_file_qsort_func);
} }

View File

@ -36,9 +36,6 @@ RETRO_BEGIN_DECLS
/* M3U file extension */ /* M3U file extension */
#define M3U_FILE_EXT "m3u" #define M3U_FILE_EXT "m3u"
/* Default maximum number of M3U entries */
#define M3U_FILE_SIZE 2048
/* Prevent direct access to m3u_file_t members */ /* Prevent direct access to m3u_file_t members */
typedef struct content_m3u_file m3u_file_t; 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 * - Returned m3u_file_t object must be free'd using
* m3u_file_free() * m3u_file_free()
* - Returns NULL in the event of an error */ * - 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 */ /* Frees specified M3U file */
void m3u_file_free(m3u_file_t *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 */ /* Returns number of entries in M3U file */
size_t m3u_file_get_size(m3u_file_t *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 /* Fetches specified M3U file entry
* - Returns false if 'idx' is invalid, or internal * - Returns false if 'idx' is invalid, or internal
* entry is NULL */ * entry is NULL */
@ -96,8 +89,9 @@ bool m3u_file_get_entry(
/* Setters */ /* Setters */
/* Adds specified entry to the M3U file /* Adds specified entry to the M3U file
* - Returns false if path is invalid, or M3U * - Returns false if path is invalid, or
* file capacity is exceeded */ * memory could not be allocated for the
* entry */
bool m3u_file_add_entry( bool m3u_file_add_entry(
m3u_file_t *m3u_file, const char *path, const char *label); m3u_file_t *m3u_file, const char *path, const char *label);

View File

@ -339,7 +339,7 @@ static void task_manual_content_scan_handler(retro_task_t *task)
task_set_progress(task, (manual_scan->m3u_index * 100) / manual_scan->m3u_list->size); task_set_progress(task, (manual_scan->m3u_index * 100) / manual_scan->m3u_list->size);
/* Load M3U file */ /* Load M3U file */
m3u_file = m3u_file_init(m3u_path, M3U_FILE_SIZE); m3u_file = m3u_file_init(m3u_path);
if (m3u_file) if (m3u_file)
{ {

View File

@ -729,7 +729,7 @@ static void task_pl_manager_clean_playlist_handler(retro_task_t *task)
task_set_progress(task, (pl_manager->m3u_index * 100) / pl_manager->m3u_list->size); task_set_progress(task, (pl_manager->m3u_index * 100) / pl_manager->m3u_list->size);
/* Load M3U file */ /* Load M3U file */
m3u_file = m3u_file_init(m3u_path, M3U_FILE_SIZE); m3u_file = m3u_file_init(m3u_path);
if (m3u_file) if (m3u_file)
{ {