libmp3splt
|
00001 /********************************************************** 00002 * libmp3splt -- library based on mp3splt, 00003 * for mp3/ogg splitting without decoding 00004 * 00005 * Copyright (c) 2002-2005 M. Trotta - <mtrotta@users.sourceforge.net> 00006 * Copyright (c) 2005-2011 Alexandru Munteanu - io_fx@yahoo.fr 00007 * 00008 *********************************************************/ 00009 00010 /********************************************************** 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software 00023 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 00024 * 02111-1307, USA. 00025 *********************************************************/ 00026 00031 #include <string.h> 00032 #include <ctype.h> 00033 00034 #include "splt.h" 00035 #include "cddb_cue_common.h" 00036 00037 #include "cue.h" 00038 00040 static void splt_cue_process_track_line(char *line_content, cue_utils *cu, splt_state *state) 00041 { 00042 // Skip the word TRACK 00043 line_content += 5; 00044 00045 if (cu->tracks == -1) 00046 { 00047 cu->tracks = 0; 00048 } 00049 00050 if (!cu->time_for_track) 00051 { 00052 splt_e_set_error_data(state, cu->file); 00053 cu->error = SPLT_INVALID_CUE_FILE; 00054 } 00055 00056 cu->performer = SPLT_FALSE; 00057 cu->title = SPLT_FALSE; 00058 cu->time_for_track = SPLT_FALSE; 00059 cu->tracks++; 00060 cu->current_track_type = SPLT_SPLITPOINT; 00061 00062 splt_tu_new_tags_if_necessary(state, cu->tracks - 1); 00063 } 00064 00065 static void remove_trailing_spaces_and_quote(char *ptr_e, char *in) 00066 { 00067 if (ptr_e) 00068 { 00069 ptr_e--; 00070 00071 while (*ptr_e == ' ' && ptr_e > in) 00072 { 00073 ptr_e--; 00074 } 00075 00076 if (ptr_e > in) 00077 { 00078 if (*ptr_e == '"') 00079 { 00080 *ptr_e = '\0'; 00081 } 00082 else 00083 { 00084 *(ptr_e + 1) = '\0'; 00085 } 00086 } 00087 } 00088 } 00089 00090 static const char *splt_cue_parse_value(char *in, int skip_last_word) 00091 { 00092 char *ptr_b = in; 00093 char *ptr_e = NULL; 00094 00095 while (*ptr_b == ' ') 00096 { 00097 ptr_b++; 00098 } 00099 00100 if (*ptr_b == '"') 00101 { 00102 ptr_b++; 00103 } 00104 00105 ptr_e = strchr(ptr_b + 1, '\0'); 00106 00107 remove_trailing_spaces_and_quote(ptr_e, in); 00108 00109 if (skip_last_word) 00110 { 00111 ptr_e = strrchr(ptr_b, ' '); 00112 remove_trailing_spaces_and_quote(ptr_e, in); 00113 } 00114 00115 return ptr_b; 00116 } 00117 00119 static int splt_cue_store_value(splt_state *state, char *in, 00120 int index, int tag_field) 00121 { 00122 if (!in) 00123 { 00124 return SPLT_OK; 00125 } 00126 00127 const char *ptr_b = splt_cue_parse_value(in, SPLT_FALSE); 00128 00129 char *out = NULL; 00130 int error = splt_su_append(&out, ptr_b, strlen(ptr_b) + 1, NULL); 00131 if (error < 0) { return error; } 00132 00133 if (tag_field == SPLT_TAGS_ARTIST) 00134 { 00135 splt_c_put_info_message_to_client(state, _("\n Artist: %s\n"), out); 00136 } 00137 else if (tag_field == SPLT_TAGS_ALBUM) 00138 { 00139 splt_c_put_info_message_to_client(state, _(" Album: %s\n"), out); 00140 } 00141 00142 error = splt_tu_set_tags_field(state, index, tag_field, out); 00143 if (out) 00144 { 00145 free(out); 00146 out = NULL; 00147 } 00148 00149 return error; 00150 } 00151 00153 static void splt_cue_process_title_line(char *line_content, cue_utils *cu, splt_state *state) 00154 { 00155 int err = SPLT_OK; 00156 00157 // Skip the word TITLE 00158 line_content += 5; 00159 00160 if (cu->tracks == -1) 00161 { 00162 if ((err = splt_cue_store_value(state, line_content, 00163 0, SPLT_TAGS_ALBUM)) != SPLT_OK) 00164 { 00165 cu->error = err; 00166 return; 00167 } 00168 } 00169 else 00170 { 00171 if (cu->tracks > 0) 00172 { 00173 if ((err = splt_cue_store_value(state, line_content, 00174 cu->tracks-1, SPLT_TAGS_TITLE)) != SPLT_OK) 00175 { 00176 cu->error = err; 00177 return; 00178 } 00179 } 00180 00181 cu->title = SPLT_TRUE; 00182 } 00183 } 00184 00186 static void splt_cue_process_performer_line(char *line_content, cue_utils *cu, splt_state *state) 00187 { 00188 int err = SPLT_OK; 00189 00190 // Skip the word PERFORMER 00191 line_content += 9; 00192 00193 if (cu->tracks == -1) 00194 { 00195 //we always have one artist in a cue file, we 00196 //put the performers if more than one artist 00197 if ((err = splt_cue_store_value(state, line_content, 00198 0, SPLT_TAGS_ARTIST)) != SPLT_OK) 00199 { 00200 cu->error = err; 00201 return; 00202 } 00203 } 00204 else 00205 { 00206 if (cu->tracks > 0) 00207 { 00208 if ((err = splt_cue_store_value(state, line_content, 00209 cu->tracks - 1, SPLT_TAGS_PERFORMER)) != SPLT_OK) 00210 { 00211 cu->error = err; 00212 return; 00213 } 00214 } 00215 00216 cu->performer = SPLT_TRUE; 00217 } 00218 00219 } 00220 00221 00223 static void splt_cue_process_index_line(char *line_content, cue_utils *cu, splt_state *state) 00224 { 00225 int err = SPLT_OK; 00226 00227 line_content += 9; 00228 00229 if (cu->tracks <= 0) 00230 { 00231 return; 00232 } 00233 00234 char *trimmed_line = splt_su_trim_spaces(line_content); 00235 00236 long hundr_seconds = splt_co_convert_to_hundreths(trimmed_line); 00237 if (hundr_seconds == -1) 00238 { 00239 splt_e_set_error_data(state, cu->file); 00240 cu->error = SPLT_INVALID_CUE_FILE; 00241 return; 00242 } 00243 00244 err = splt_sp_append_splitpoint(state, hundr_seconds, NULL, 00245 cu->current_track_type); 00246 if (err < 0) { cu->error = err; return; } 00247 00248 cu->time_for_track = SPLT_TRUE; 00249 cu->counter++; 00250 } 00251 00253 static void splt_cue_process_rem_line(char *line_content, cue_utils *cu, splt_state *state) 00254 { 00255 char *linetail; 00256 00257 // Skip the word REM 00258 line_content += 3; 00259 00260 // Skip all leading whitespace after the word REM 00261 while ((*line_content==' ')||(*line_content=='\t')) line_content++; 00262 00263 if((linetail=strstr(line_content,"CREATOR"))!=NULL) 00264 { 00265 // Skip the word "CREATOR" 00266 linetail += 7; 00267 00268 if(strstr(linetail,"MP3SPLT_GTK")!=NULL) 00269 { 00270 cu->file_has_been_created_by_us = SPLT_TRUE; 00271 } 00272 } 00273 else if((linetail=strstr(line_content,"SPLT_TITLE_IS_FILENAME"))!=NULL) 00274 { 00275 cu->title_is_filename = SPLT_TRUE; 00276 } 00277 else if((linetail=strstr(line_content,"NOKEEP"))!=NULL) 00278 { 00279 if (cu->tracks >= 0) 00280 cu->current_track_type=SPLT_SKIPPOINT; 00281 } 00282 } 00283 00285 static void splt_cue_process_file_line(char *line_content, cue_utils *cu, splt_state *state) 00286 { 00287 if (!splt_o_get_int_option(state, SPLT_OPT_SET_FILE_FROM_CUE_IF_FILE_TAG_FOUND)) 00288 { 00289 return; 00290 } 00291 00292 // Skip the word FILE 00293 line_content += 4; 00294 00295 int err = SPLT_OK; 00296 00297 const char *file_from_cue = splt_cue_parse_value(line_content, SPLT_TRUE); 00298 00299 if (splt_io_check_if_file(NULL, file_from_cue)) 00300 { 00301 err = splt_t_set_filename_to_split(state, file_from_cue); 00302 if (err < 0) { cu->error = err; } 00303 return; 00304 } 00305 00306 char *file_from_cue_with_path = NULL; 00307 splt_su_copy(cu->file, &file_from_cue_with_path); 00308 splt_su_keep_path_and_remove_filename(file_from_cue_with_path); 00309 splt_su_append_str(&file_from_cue_with_path, SPLT_DIRSTR, file_from_cue, NULL); 00310 00311 if (splt_io_check_if_file(NULL, file_from_cue_with_path)) 00312 { 00313 err = splt_t_set_filename_to_split(state, file_from_cue_with_path); 00314 } 00315 00316 if (file_from_cue_with_path) 00317 { 00318 free(file_from_cue_with_path); 00319 file_from_cue_with_path = NULL; 00320 } 00321 00322 if (err < 0) { cu->error = err; return; } 00323 } 00324 00328 static void splt_cue_process_line(char **l, cue_utils *cu, splt_state *state) 00329 { 00330 if (!l || !*l) { return; } 00331 00332 char *line = *l; 00333 00334 splt_su_line_to_unix(line); 00335 splt_su_str_cut_last_char(line); 00336 00337 splt_t_clean_one_split_data(state, cu->tracks); 00338 00339 char *line_content = NULL; 00340 if (((line_content = strstr(line, "TRACK")) != NULL) 00341 && (strstr(line, "AUDIO") != NULL)) 00342 { 00343 splt_cue_process_track_line(line_content, cu, state); 00344 } 00345 else if ((line_content = strstr(line, "REM")) != NULL) 00346 { 00347 splt_cue_process_rem_line(line_content, cu, state); 00348 } 00349 else if ((line_content = strstr(line, "TITLE")) != NULL) 00350 { 00351 splt_cue_process_title_line(line_content, cu, state); 00352 } 00353 else if ((line_content = strstr(line, "PERFORMER")) != NULL) 00354 { 00355 splt_cue_process_performer_line(line_content, cu, state); 00356 } 00357 else if ((line_content = strstr(line, "INDEX 01")) != NULL) 00358 { 00359 splt_cue_process_index_line(line_content, cu, state); 00360 } 00361 else if ((line_content = strstr(line, "FILE")) != NULL) 00362 { 00363 splt_cue_process_file_line(line_content, cu, state); 00364 } 00365 00366 free(*l); 00367 *l = NULL; 00368 } 00369 00370 00371 /* Malloc memory for and initialize a cue_utils structure 00372 00373 \param error Contains the libmp3splt error number if any error 00374 occoured in this step. 00375 \return The address of the structure 00376 */ 00377 static cue_utils *splt_cue_cu_new(int *error) 00378 { 00379 cue_utils *cu = malloc(sizeof(cue_utils)); 00380 if (cu == NULL) 00381 { 00382 *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY; 00383 return NULL; 00384 } 00385 00386 cu->tracks = -1; 00387 cu->time_for_track = SPLT_TRUE; 00388 cu->performer = SPLT_FALSE; 00389 cu->title = SPLT_FALSE; 00390 cu->counter = 0; 00391 cu->file = NULL; 00392 cu->error = SPLT_OK; 00393 cu->current_track_type = SPLT_SPLITPOINT; 00394 cu->title_is_filename = SPLT_FALSE; 00395 cu->file_has_been_created_by_us = SPLT_FALSE; 00396 00397 return cu; 00398 } 00399 00405 static void splt_cue_cu_free(cue_utils **cu) 00406 { 00407 if (!cu || !*cu) 00408 { 00409 return; 00410 } 00411 00412 free(*cu); 00413 *cu = NULL; 00414 } 00415 00425 int splt_cue_put_splitpoints(const char *file, splt_state *state, int *error) 00426 { 00427 if (file == NULL) 00428 { 00429 *error = SPLT_INVALID_CUE_FILE; 00430 return 0; 00431 } 00432 00433 splt_c_put_info_message_to_client(state, 00434 _(" reading informations from CUE file %s ...\n"),file); 00435 00436 splt_t_free_splitpoints_tags(state); 00437 00438 *error = SPLT_CUE_OK; 00439 00440 int err = SPLT_OK; 00441 FILE *file_input = NULL; 00442 char *line = NULL; 00443 int tracks = -1; 00444 00445 cue_utils *cu = splt_cue_cu_new(&err); 00446 00447 if (err < 0) { *error = err; return tracks; } 00448 cu->file = file; 00449 00450 //TODO: .cue #REM GENRE support 00451 err = splt_tu_set_tags_field(state, 0, SPLT_TAGS_GENRE, SPLT_UNDEFINED_GENRE); 00452 if (err != SPLT_OK) 00453 { 00454 *error = err; 00455 return tracks; 00456 } 00457 00458 if (!(file_input=splt_io_fopen(file, "r"))) 00459 { 00460 splt_e_set_strerror_msg_with_data(state, file); 00461 *error = SPLT_ERROR_CANNOT_OPEN_FILE; 00462 return tracks; 00463 } 00464 00465 if (fseek(file_input, 0, SEEK_SET) != 0) 00466 { 00467 splt_e_set_strerror_msg_with_data(state, file); 00468 *error = SPLT_ERROR_SEEKING_FILE; 00469 goto function_end; 00470 } 00471 00472 while ((line = splt_io_readline(file_input, error)) != NULL) 00473 { 00474 if (*error < 0) { goto function_end; } 00475 00476 splt_cue_process_line(&line, cu, state); 00477 tracks = cu->tracks; 00478 if (cu->error < 0) { *error = cu->error; goto function_end; } 00479 } 00480 00481 // Append a split point at the end of the file 00482 // If the file has been created by us this has already been done 00483 // and we can skip this step. 00484 if(!cu->file_has_been_created_by_us) 00485 err = splt_sp_append_splitpoint(state, LONG_MAX, 00486 _("description here"), cu->current_track_type); 00487 00488 if (cu->counter == 0) 00489 { 00490 splt_e_set_error_data(state, file); 00491 *error = SPLT_INVALID_CUE_FILE; 00492 goto function_end; 00493 } 00494 00495 if (!cu->time_for_track) 00496 { 00497 tracks--; 00498 } 00499 00500 // Generate filenames using the tags we got 00501 splt_cc_put_filenames_from_tags(state, tracks, error); 00502 00503 // If mp3splt_gtk has generated the cue file 00504 // splt_cc_put_filenames_from_tags has now auto-generated 00505 // filenames that contain the intended filename (that was 00506 // written to the TITLE tag). 00507 // Which means we have to correct this by copying the 00508 // TITLE tags to the filenames. 00509 00510 if(cu->title_is_filename) 00511 { 00512 int i; 00513 for(i=0;i<tracks;i++) 00514 { 00515 splt_sp_set_splitpoint_name(state, i, 00516 splt_tu_get_tags_field(state, i, SPLT_TAGS_TITLE)); 00517 } 00518 } 00519 00520 function_end: 00521 splt_cue_cu_free(&cu); 00522 00523 if (line) 00524 { 00525 free(line); 00526 line = NULL; 00527 } 00528 00529 if (fclose(file_input) != 0) 00530 { 00531 splt_e_set_strerror_msg_with_data(state, file); 00532 *error = SPLT_ERROR_CANNOT_CLOSE_FILE; 00533 } 00534 file_input = NULL; 00535 00536 if (*error >= 0) 00537 { 00538 splt_c_put_info_message_to_client(state, _(" Tracks: %d\n\n"), tracks); 00539 } 00540 00541 return tracks; 00542 } 00543 00553 static void splt_cue_write_title_performer(splt_state *state, FILE *file_output, 00554 int tags_index, short with_spaces, short write_album) 00555 { 00556 splt_tags *tags = NULL; 00557 if (tags_index >= 0) 00558 { 00559 tags = splt_tu_get_tags_at(state, tags_index); 00560 } 00561 else 00562 { 00563 tags = splt_tu_get_current_tags(state); 00564 } 00565 00566 if (tags) 00567 { 00568 if (write_album) 00569 { 00570 if (tags->album) 00571 { 00572 if (with_spaces) { fprintf(file_output, " "); } 00573 fprintf(file_output, "TITLE \"%s\"\n", tags->album); 00574 } 00575 } 00576 else 00577 { 00578 if (tags->title) 00579 { 00580 if (with_spaces) { fprintf(file_output, " "); } 00581 fprintf(file_output, "TITLE \"%s\"\n", tags->title); 00582 } 00583 } 00584 00585 char *performer = splt_tu_get_artist_or_performer_ptr(tags); 00586 if (performer) 00587 { 00588 if (with_spaces) { fprintf(file_output, " "); } 00589 fprintf(file_output, "PERFORMER \"%s\"\n", performer); 00590 } 00591 } 00592 else 00593 { 00594 if (with_spaces) { fprintf(file_output, " "); } 00595 fprintf(file_output, "TITLE \"\"\n"); 00596 if (with_spaces) { fprintf(file_output, " "); } 00597 fprintf(file_output, "PERFORMER \"\"\n"); 00598 } 00599 } 00600 00611 void splt_cue_export_to_file(splt_state *state, const char *out_file, 00612 short stop_at_total_time, int *error) 00613 { 00614 int err = SPLT_OK; 00615 00616 int num_of_splitpoints = splt_t_get_splitnumber(state); 00617 if (num_of_splitpoints <= 0) 00618 { 00619 return; 00620 } 00621 00622 long total_time = splt_t_get_total_time(state); 00623 FILE *file_output = NULL; 00624 00625 splt_d_print_debug(state, "Cue output file without output path = _%s_\n", out_file); 00626 00627 char *dup_out_file = NULL; 00628 err = splt_su_copy(out_file, &dup_out_file); 00629 if (err < 0) { *error = err; return; } 00630 char *cue_out_file = splt_su_get_file_with_output_path(state, dup_out_file, &err); 00631 free(dup_out_file); 00632 dup_out_file = NULL; 00633 if (err < 0) { *error = err; goto end; } 00634 00635 splt_d_print_debug(state, "Cue output file with output path = _%s_\n", cue_out_file); 00636 00637 if (!(file_output = splt_io_fopen(cue_out_file, "w"))) 00638 { 00639 splt_e_set_strerror_msg_with_data(state, cue_out_file); 00640 *error = SPLT_ERROR_CANT_WRITE_TO_OUTPUT_FILE; 00641 goto end; 00642 } 00643 00644 splt_cue_write_title_performer(state, file_output, 0, SPLT_FALSE, SPLT_TRUE); 00645 00646 char *fname = splt_t_get_filename_to_split(state); 00647 00648 char new_upper_ext[10] = { '\0' }; 00649 const char *upper_ext = splt_p_get_upper_extension(state, &err); 00650 int i = 0; 00651 for (i = 1;i < strlen(upper_ext);i++) 00652 { 00653 new_upper_ext[i-1] = upper_ext[i]; 00654 } 00655 00656 fprintf(file_output, "FILE \"%s\" %s\n", fname, new_upper_ext); 00657 if (err < 0) { *error = err; goto end; } 00658 00659 splt_t_set_current_split(state, 0); 00660 for (i = 0;i < num_of_splitpoints;i++) 00661 { 00662 long splitpoint = splt_sp_get_splitpoint_value(state, i, &err); 00663 if (err < 0) { *error = err; break; } 00664 00665 //todo: splitpoint can be slightly != than total_time sometimes 00666 // (test with silence and cue) 00667 if (stop_at_total_time && 00668 (total_time > 0 && splitpoint >= total_time)) 00669 { 00670 break; 00671 } 00672 00673 fprintf(file_output, " TRACK %02d AUDIO\n", i+1); 00674 00675 splt_cue_write_title_performer(state, file_output, -1, SPLT_TRUE, SPLT_FALSE); 00676 00677 long mins = 0, secs = 0, hundr = 0; 00678 splt_sp_get_mins_secs_hundr_from_splitpoint(splitpoint, &mins, &secs, &hundr); 00679 fprintf(file_output, " INDEX 01 %02ld:%02ld:%02ld\n", mins, secs, hundr); 00680 00681 splt_t_current_split_next(state); 00682 } 00683 00684 end: 00685 fflush(file_output); 00686 if (fclose(file_output) != 0) 00687 { 00688 splt_e_set_strerror_msg_with_data(state, cue_out_file); 00689 *error = SPLT_ERROR_CANNOT_CLOSE_FILE; 00690 } 00691 file_output = NULL; 00692 00693 splt_c_put_info_message_to_client(state, 00694 _(" CUE file '%s' created.\n"), cue_out_file); 00695 00696 if (cue_out_file) 00697 { 00698 free(cue_out_file); 00699 cue_out_file = NULL; 00700 } 00701 } 00702