diff options
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | src/cue/cue_parser.c | 54 |
2 files changed, 48 insertions, 7 deletions
@@ -9,6 +9,7 @@ ver 0.17.3 (2012/??/??) - ffmpeg: support planar audio * playlist: - cue: fix memory leak + - cue: fix CUE files with only one track ver 0.17.2 (2012/09/30) * protocol: diff --git a/src/cue/cue_parser.c b/src/cue/cue_parser.c index 4031d6c42..9ccc3bcdd 100644 --- a/src/cue/cue_parser.c +++ b/src/cue/cue_parser.c @@ -80,6 +80,13 @@ struct cue_parser { * start time of the current song. */ bool last_updated; + + /** + * Tracks whether cue_parser_finish() has been called. If + * true, then all remaining (partial) results will be + * delivered by cue_parser_get(). + */ + bool end; }; struct cue_parser * @@ -92,6 +99,7 @@ cue_parser_new(void) parser->current = NULL; parser->previous = NULL; parser->finished = NULL; + parser->end = false; return parser; } @@ -223,10 +231,32 @@ cue_parse_position(const char *p) return minutes * 60000 + seconds * 1000 + frames * 1000 / 75; } +/** + * Commit the current song. It will be moved to "previous", so the + * next song may soon edit its end time (using the next song's start + * time). + */ +static void +cue_parser_commit(struct cue_parser *parser) +{ + /* the caller of this library must call cue_parser_get() often + enough */ + assert(parser->finished == NULL); + assert(!parser->end); + + if (parser->current == NULL) + return; + + parser->finished = parser->previous; + parser->previous = parser->current; + parser->current = NULL; +} + static void cue_parser_feed2(struct cue_parser *parser, char *p) { assert(parser != NULL); + assert(!parser->end); assert(p != NULL); const char *command = cue_next_token(&p); @@ -257,7 +287,7 @@ cue_parser_feed2(struct cue_parser *parser, char *p) else if (parser->state == TRACK) cue_add_tag(parser->current->tag, TAG_TITLE, p); } else if (strcmp(command, "FILE") == 0) { - cue_parser_finish(parser); + cue_parser_commit(parser); const char *filename = cue_next_value(&p); if (filename == NULL) @@ -280,7 +310,7 @@ cue_parser_feed2(struct cue_parser *parser, char *p) } else if (parser->state == IGNORE_FILE) { return; } else if (strcmp(command, "TRACK") == 0) { - cue_parser_finish(parser); + cue_parser_commit(parser); const char *nr = cue_next_token(&p); if (nr == NULL) @@ -332,6 +362,7 @@ void cue_parser_feed(struct cue_parser *parser, const char *line) { assert(parser != NULL); + assert(!parser->end); assert(line != NULL); char *allocated = g_strdup(line); @@ -342,12 +373,12 @@ cue_parser_feed(struct cue_parser *parser, const char *line) void cue_parser_finish(struct cue_parser *parser) { - if (parser->finished != NULL) - song_free(parser->finished); + if (parser->end) + /* has already been called, ignore */ + return; - parser->finished = parser->previous; - parser->previous = parser->current; - parser->current = NULL; + cue_parser_commit(parser); + parser->end = true; } struct song * @@ -355,6 +386,15 @@ cue_parser_get(struct cue_parser *parser) { assert(parser != NULL); + if (parser->finished == NULL && parser->end) { + /* cue_parser_finish() has been called already: + deliver all remaining (partial) results */ + assert(parser->current == NULL); + + parser->finished = parser->previous; + parser->previous = NULL; + } + struct song *song = parser->finished; parser->finished = NULL; return song; |