2626#include <lists/string_list.h>
2727#include <file/file_path.h>
2828#include <streams/file_stream.h>
29+ #include <array/rbuf.h>
2930
3031#include <formats/m3u_file.h>
3132
5051struct content_m3u_file
5152{
5253 char * path ;
53- size_t size ;
54- size_t capacity ;
5554 m3u_file_entry_t * entries ;
5655};
5756
@@ -66,6 +65,7 @@ static bool m3u_file_load(m3u_file_t *m3u_file)
6665 int64_t file_len = 0 ;
6766 uint8_t * file_buf = NULL ;
6867 struct string_list * lines = NULL ;
68+ bool success = false;
6969 size_t i ;
7070 char entry_path [PATH_MAX_LENGTH ];
7171 char entry_label [PATH_MAX_LENGTH ];
@@ -74,27 +74,28 @@ static bool m3u_file_load(m3u_file_t *m3u_file)
7474 entry_label [0 ] = '\0' ;
7575
7676 if (!m3u_file )
77- return false ;
77+ goto end ;
7878
7979 /* Check whether file exists
8080 * > If path is empty, then an error
8181 * has occurred... */
8282 if (string_is_empty (m3u_file -> path ))
83- return false ;
83+ goto end ;
8484
8585 /* > File must have the correct extension */
8686 file_ext = path_get_extension (m3u_file -> path );
8787
88- if (string_is_empty (file_ext ))
89- return false;
90-
91- if (!string_is_equal_noncase (file_ext , M3U_FILE_EXT ))
92- return false;
88+ if (string_is_empty (file_ext ) ||
89+ !string_is_equal_noncase (file_ext , M3U_FILE_EXT ))
90+ goto end ;
9391
9492 /* > If file does not exist, no action
9593 * is required */
9694 if (!path_is_valid (m3u_file -> path ))
97- return true;
95+ {
96+ success = true;
97+ goto end ;
98+ }
9899
99100 /* Read file from disk */
100101 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)
105106
106107 /* File buffer no longer required */
107108 if (file_buf )
109+ {
108110 free (file_buf );
111+ file_buf = NULL ;
112+ }
109113 }
114+ /* File IO error... */
110115 else
111- {
112- /* File IO error... */
113- if (file_buf )
114- free (file_buf );
115- return false;
116- }
116+ goto end ;
117117
118118 /* If file was empty, no action is required */
119119 if (!lines )
120- return true;
120+ {
121+ success = true;
122+ goto end ;
123+ }
121124
122125 /* Parse lines of file */
123126 for (i = 0 ; i < lines -> size ; i ++ )
124127 {
125- size_t m3u_size ;
126128 const char * line = lines -> elems [i ].data ;
127129
128130 if (string_is_empty (line ))
129131 continue ;
130132
131133 /* Determine line 'type' */
132- m3u_size = STRLEN_CONST (M3U_FILE_NONSTD_LABEL );
133134
134135 /* > '#LABEL:' */
135- if (!strncmp (
136- line , M3U_FILE_NONSTD_LABEL ,
137- m3u_size ))
136+ if (string_starts_with_size (line , M3U_FILE_NONSTD_LABEL ,
137+ STRLEN_CONST (M3U_FILE_NONSTD_LABEL )))
138138 {
139139 /* Label is the string to the right
140140 * of '#LABEL:' */
141- const char * label = line + m3u_size ;
141+ const char * label = line + STRLEN_CONST ( M3U_FILE_NONSTD_LABEL ) ;
142142
143143 if (!string_is_empty (label ))
144144 {
145145 strlcpy (
146- entry_label , line + m3u_size ,
146+ entry_label , line + STRLEN_CONST ( M3U_FILE_NONSTD_LABEL ) ,
147147 sizeof (entry_label ));
148148 string_trim_whitespace (entry_label );
149149 }
150150 }
151151 /* > '#EXTINF:' */
152- else if (!strncmp (
153- line , M3U_FILE_EXTSTD_LABEL ,
152+ else if (string_starts_with_size (line , M3U_FILE_EXTSTD_LABEL ,
154153 STRLEN_CONST (M3U_FILE_EXTSTD_LABEL )))
155154 {
156155 /* Label is the string to the right
@@ -210,24 +209,37 @@ static bool m3u_file_load(m3u_file_t *m3u_file)
210209 }
211210
212211 /* Add entry to file
213- * > Ignore errors here - invalid entries
214- * will just be omitted */
215- m3u_file_add_entry (m3u_file , entry_path , entry_label );
212+ * > Note: The only way that m3u_file_add_entry()
213+ * can fail here is if we run out of memory.
214+ * This is a critical error, and m3u_file must
215+ * be considered invalid in this case */
216+ if (!string_is_empty (entry_path ) &&
217+ !m3u_file_add_entry (m3u_file , entry_path , entry_label ))
218+ goto end ;
216219
217220 /* Reset entry_path/entry_label */
218221 entry_path [0 ] = '\0' ;
219222 entry_label [0 ] = '\0' ;
220223 }
221224 }
222225
226+ success = true;
227+
228+ end :
223229 /* Clean up */
224230 if (lines )
225231 {
226232 string_list_free (lines );
227233 lines = NULL ;
228234 }
229235
230- return true;
236+ if (file_buf )
237+ {
238+ free (file_buf );
239+ file_buf = NULL ;
240+ }
241+
242+ return success ;
231243}
232244
233245/* Creates and initialises an M3U file
@@ -238,16 +250,15 @@ static bool m3u_file_load(m3u_file_t *m3u_file)
238250 * - Returned m3u_file_t object must be free'd using
239251 * m3u_file_free()
240252 * - Returns NULL in the event of an error */
241- m3u_file_t * m3u_file_init (const char * path , size_t size )
253+ m3u_file_t * m3u_file_init (const char * path )
242254{
243- m3u_file_entry_t * entries = NULL ;
244- m3u_file_t * m3u_file = NULL ;
255+ m3u_file_t * m3u_file = NULL ;
245256 char m3u_path [PATH_MAX_LENGTH ];
246257
247258 m3u_path [0 ] = '\0' ;
248259
249260 /* Sanity check */
250- if (string_is_empty (path ) || ( size < 1 ) )
261+ if (string_is_empty (path ))
251262 return NULL ;
252263
253264 /* Get 'real' file path */
@@ -258,27 +269,17 @@ m3u_file_t *m3u_file_init(const char *path, size_t size)
258269 return NULL ;
259270
260271 /* Create m3u_file_t object */
261- m3u_file = (m3u_file_t * )calloc ( 1 , sizeof (* m3u_file ));
272+ m3u_file = (m3u_file_t * )malloc ( sizeof (* m3u_file ));
262273
263274 if (!m3u_file )
264275 return NULL ;
265276
266- /* Create m3u_file_entry_t array */
267- entries = (m3u_file_entry_t * )calloc (size , sizeof (* entries ));
268-
269- if (!entries )
270- {
271- free (m3u_file );
272- return NULL ;
273- }
277+ /* Initialise members */
278+ m3u_file -> path = NULL ;
279+ m3u_file -> entries = NULL ;
274280
275281 /* Copy file path */
276- m3u_file -> path = strdup (m3u_path );
277-
278- /* Set remaining values */
279- m3u_file -> size = 0 ;
280- m3u_file -> capacity = size ;
281- m3u_file -> entries = entries ;
282+ m3u_file -> path = strdup (m3u_path );
282283
283284 /* Read existing file contents from
284285 * disk, if required */
@@ -327,15 +328,14 @@ void m3u_file_free(m3u_file_t *m3u_file)
327328 /* Free entries */
328329 if (m3u_file -> entries )
329330 {
330- for (i = 0 ; i < m3u_file -> size ; i ++ )
331+ for (i = 0 ; i < RBUF_LEN ( m3u_file -> entries ) ; i ++ )
331332 {
332333 m3u_file_entry_t * entry = & m3u_file -> entries [i ];
333334 m3u_file_free_entry (entry );
334335 }
335336
336- free (m3u_file -> entries );
337+ RBUF_FREE (m3u_file -> entries );
337338 }
338- m3u_file -> entries = NULL ;
339339
340340 free (m3u_file );
341341}
@@ -357,17 +357,7 @@ size_t m3u_file_get_size(m3u_file_t *m3u_file)
357357 if (!m3u_file )
358358 return 0 ;
359359
360- return m3u_file -> size ;
361- }
362-
363- /* Returns maximum number of entries permitted
364- * in M3U file */
365- size_t m3u_file_get_capacity (m3u_file_t * m3u_file )
366- {
367- if (!m3u_file )
368- return 0 ;
369-
370- return m3u_file -> capacity ;
360+ return RBUF_LEN (m3u_file -> entries );
371361}
372362
373363/* Fetches specified M3U file entry
@@ -378,8 +368,7 @@ bool m3u_file_get_entry(
378368{
379369 if (!m3u_file ||
380370 !entry ||
381- (idx >= m3u_file -> size ) ||
382- !m3u_file -> entries )
371+ (idx >= RBUF_LEN (m3u_file -> entries )))
383372 return false;
384373
385374 * entry = & m3u_file -> entries [idx ];
@@ -393,30 +382,35 @@ bool m3u_file_get_entry(
393382/* Setters */
394383
395384/* Adds specified entry to the M3U file
396- * - Returns false if path is invalid, or M3U
397- * file capacity is exceeded */
385+ * - Returns false if path is invalid, or
386+ * memory could not be allocated for the
387+ * entry */
398388bool m3u_file_add_entry (
399389 m3u_file_t * m3u_file , const char * path , const char * label )
400390{
401391 m3u_file_entry_t * entry = NULL ;
392+ size_t num_entries ;
402393 char full_path [PATH_MAX_LENGTH ];
403394
404395 full_path [0 ] = '\0' ;
405396
406- if (!m3u_file ||
407- !m3u_file -> entries ||
408- (m3u_file -> size >= m3u_file -> capacity ) ||
409- string_is_empty (path ))
397+ if (!m3u_file || string_is_empty (path ))
410398 return false;
411399
412- /* Get new entry at end of list */
413- entry = & m3u_file -> entries [ m3u_file -> size ] ;
400+ /* Get current number of file entries */
401+ num_entries = RBUF_LEN ( m3u_file -> entries ) ;
414402
415- if (!entry )
403+ /* Attempt to allocate memory for new entry */
404+ if (!RBUF_TRYFIT (m3u_file -> entries , num_entries + 1 ))
416405 return false;
417406
418- /* Ensure entry is free'd */
419- m3u_file_free_entry (entry );
407+ /* Allocation successful - increment array size */
408+ RBUF_RESIZE (m3u_file -> entries , num_entries + 1 );
409+
410+ /* Fetch entry at end of list, and zero-initialise
411+ * members */
412+ entry = & m3u_file -> entries [num_entries ];
413+ memset (entry , 0 , sizeof (* entry ));
420414
421415 /* Copy path and label */
422416 entry -> path = strdup (path );
@@ -444,9 +438,6 @@ bool m3u_file_add_entry(
444438
445439 entry -> full_path = strdup (full_path );
446440
447- /* Increment size counter */
448- m3u_file -> size ++ ;
449-
450441 return true;
451442}
452443
@@ -460,14 +451,14 @@ void m3u_file_clear(m3u_file_t *m3u_file)
460451
461452 if (m3u_file -> entries )
462453 {
463- for (i = 0 ; i < m3u_file -> size ; i ++ )
454+ for (i = 0 ; i < RBUF_LEN ( m3u_file -> entries ) ; i ++ )
464455 {
465456 m3u_file_entry_t * entry = & m3u_file -> entries [i ];
466457 m3u_file_free_entry (entry );
467458 }
468- }
469459
470- m3u_file -> size = 0 ;
460+ RBUF_FREE (m3u_file -> entries );
461+ }
471462}
472463
473464/* Saving */
@@ -510,7 +501,7 @@ bool m3u_file_save(
510501 return false;
511502
512503 /* Loop over entries */
513- for (i = 0 ; i < m3u_file -> size ; i ++ )
504+ for (i = 0 ; i < RBUF_LEN ( m3u_file -> entries ) ; i ++ )
514505 {
515506 m3u_file_entry_t * entry = & m3u_file -> entries [i ];
516507 char entry_path [PATH_MAX_LENGTH ];
@@ -593,13 +584,18 @@ static int m3u_file_qsort_func(
593584/* Sorts M3U file entries in alphabetical order */
594585void m3u_file_qsort (m3u_file_t * m3u_file )
595586{
596- if (!m3u_file ||
597- !m3u_file -> entries ||
598- (m3u_file -> size < 2 ))
587+ size_t num_entries ;
588+
589+ if (!m3u_file )
590+ return ;
591+
592+ num_entries = RBUF_LEN (m3u_file -> entries );
593+
594+ if (num_entries < 2 )
599595 return ;
600596
601597 qsort (
602- m3u_file -> entries , m3u_file -> size ,
598+ m3u_file -> entries , num_entries ,
603599 sizeof (m3u_file_entry_t ),
604600 (int (* )(const void * , const void * ))m3u_file_qsort_func );
605601}
0 commit comments