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, 00025 * USA. 00026 *********************************************************/ 00027 00032 #include <string.h> 00033 #include <sys/stat.h> 00034 #include <unistd.h> 00035 #include <dirent.h> 00036 #include <errno.h> 00037 00038 #ifdef __WIN32__ 00039 #include <shlwapi.h> 00040 #endif 00041 00042 #include "splt.h" 00043 00044 static int splt_u_fname_is_directory_parent(char *fname, int fname_size); 00045 00046 int splt_io_input_is_stdin(splt_state *state) 00047 { 00048 char *filename = splt_t_get_filename_to_split(state); 00049 00050 if (filename && filename[0] != '\0') 00051 { 00052 if ((strcmp(filename,"-") == 0) || 00053 (filename[strlen(filename)-1] == '-')) 00054 { 00055 return SPLT_TRUE; 00056 } 00057 } 00058 00059 return SPLT_FALSE; 00060 } 00061 00062 int splt_io_input_is_stdout(splt_state *state) 00063 { 00064 const char *oformat = splt_of_get_oformat(state); 00065 00066 if (oformat && oformat[0] != '\0') 00067 { 00068 if ((strcmp(oformat,"-") == 0)) 00069 { 00070 return SPLT_TRUE; 00071 } 00072 else 00073 { 00074 return SPLT_FALSE; 00075 } 00076 } 00077 00078 return SPLT_FALSE; 00079 } 00080 00081 static int splt_io_file_type_is(const char *fname, int file_type) 00082 { 00083 mode_t st_mode; 00084 int status = splt_io_stat(fname, &st_mode, NULL); 00085 if (status == 0) 00086 { 00087 if ((st_mode & S_IFMT) == file_type) 00088 { 00089 return SPLT_TRUE; 00090 } 00091 } 00092 00093 return SPLT_FALSE; 00094 } 00095 00096 #ifndef __WIN32__ 00097 static char *splt_io_readlink(const char *fname) 00098 { 00099 int bufsize = 1024; 00100 00101 while (bufsize < INT_MAX) 00102 { 00103 char *linked_fname = malloc(sizeof(char) * bufsize); 00104 if (linked_fname == NULL) 00105 { 00106 return NULL; 00107 } 00108 00109 ssize_t real_link_size = readlink(fname, linked_fname, bufsize); 00110 if (real_link_size == -1) 00111 { 00112 free(linked_fname); 00113 return NULL; 00114 } 00115 00116 if (real_link_size < bufsize) 00117 { 00118 linked_fname[real_link_size] = '\0'; 00119 return linked_fname; 00120 } 00121 00122 free(linked_fname); 00123 bufsize += 1024; 00124 } 00125 00126 return NULL; 00127 } 00128 00129 char *splt_io_get_linked_fname(const char *fname, int *number_of_symlinks) 00130 { 00131 char *previous_linked_fname = NULL; 00132 00133 char *linked_fname = splt_io_readlink(fname); 00134 if (!linked_fname) 00135 { 00136 return NULL; 00137 } 00138 00139 int count = 0; 00140 while (linked_fname != NULL) 00141 { 00142 if (previous_linked_fname) 00143 { 00144 free(previous_linked_fname); 00145 } 00146 previous_linked_fname = linked_fname; 00147 linked_fname = splt_io_readlink(linked_fname); 00148 00149 count++; 00150 if (count > MAX_SYMLINKS) 00151 { 00152 if (previous_linked_fname) 00153 { 00154 free(previous_linked_fname); 00155 previous_linked_fname = NULL; 00156 } 00157 if (linked_fname) 00158 { 00159 free(linked_fname); 00160 } 00161 if (number_of_symlinks) 00162 { 00163 *number_of_symlinks = MAX_SYMLINKS; 00164 } 00165 return NULL; 00166 } 00167 } 00168 00169 if (number_of_symlinks) 00170 { 00171 *number_of_symlinks = count; 00172 } 00173 00174 linked_fname = previous_linked_fname; 00175 00176 if (linked_fname[0] == SPLT_DIRCHAR) 00177 { 00178 return linked_fname; 00179 } 00180 00181 char *slash_ptr = strrchr(fname, SPLT_DIRCHAR); 00182 if (slash_ptr == NULL) 00183 { 00184 return linked_fname; 00185 } 00186 00187 char *linked_fname_with_path = NULL; 00188 00189 size_t path_size = slash_ptr - fname + 1; 00190 int err = splt_su_append(&linked_fname_with_path, fname, path_size, NULL); 00191 if (err != SPLT_OK) 00192 { 00193 free(linked_fname); 00194 return NULL; 00195 } 00196 00197 err = splt_su_append_str(&linked_fname_with_path, linked_fname, NULL); 00198 if (err != SPLT_OK) 00199 { 00200 free(linked_fname); 00201 free(linked_fname_with_path); 00202 return NULL; 00203 } 00204 00205 free(linked_fname); 00206 linked_fname = NULL; 00207 00208 return linked_fname_with_path; 00209 } 00210 00211 static int splt_io_linked_file_type_is(const char *fname, int file_type) 00212 { 00213 int linked_file_is_of_type = SPLT_FALSE; 00214 00215 int number_of_symlinks = 0; 00216 char *linked_fname = splt_io_get_linked_fname(fname, &number_of_symlinks); 00217 if (linked_fname) 00218 { 00219 if (splt_io_file_type_is(linked_fname, file_type)) 00220 { 00221 linked_file_is_of_type = SPLT_TRUE; 00222 } 00223 00224 free(linked_fname); 00225 linked_fname = NULL; 00226 } 00227 00228 if (number_of_symlinks == MAX_SYMLINKS) 00229 { 00230 errno = ELOOP; 00231 } 00232 00233 return linked_file_is_of_type; 00234 } 00235 #endif 00236 00237 int splt_io_check_if_directory(const char *fname) 00238 { 00239 #ifdef __WIN32__ 00240 int is_file = splt_io_check_if_file(NULL, fname); 00241 if (is_file) 00242 { 00243 return SPLT_FALSE; 00244 } 00245 00246 if (splt_w32_check_if_encoding_is_utf8(fname)) 00247 { 00248 wchar_t *wpath = splt_w32_utf8_to_utf16(fname); 00249 if (PathFileExistsW(wpath) == 1) 00250 { 00251 free(wpath); 00252 return SPLT_TRUE; 00253 } 00254 00255 free(wpath); 00256 return SPLT_FALSE; 00257 } 00258 else 00259 { 00260 if (PathFileExistsA(fname) == 1) 00261 { 00262 return SPLT_TRUE; 00263 } 00264 00265 return SPLT_FALSE; 00266 } 00267 #endif 00268 00269 if (fname != NULL) 00270 { 00271 if (splt_io_file_type_is(fname, S_IFDIR)) 00272 { 00273 return SPLT_TRUE; 00274 } 00275 00276 #ifndef __WIN32__ 00277 int is_link = splt_io_file_type_is(fname, S_IFLNK); 00278 if (is_link && splt_io_linked_file_type_is(fname, S_IFDIR)) 00279 { 00280 return SPLT_TRUE; 00281 } 00282 #endif 00283 } 00284 00285 return SPLT_FALSE; 00286 } 00287 00288 int splt_io_check_if_file(splt_state *state, const char *fname) 00289 { 00290 errno = 0; 00291 00292 if (fname != NULL) 00293 { 00294 //stdin: consider as file 00295 if (fname[0] != '\0' && fname[strlen(fname)-1] == '-') 00296 { 00297 return SPLT_TRUE; 00298 } 00299 00300 if (splt_io_file_type_is(fname, S_IFREG)) 00301 { 00302 return SPLT_TRUE; 00303 } 00304 00305 #ifndef __WIN32__ 00306 int is_link = splt_io_file_type_is(fname, S_IFLNK); 00307 if (is_link && splt_io_linked_file_type_is(fname, S_IFREG)) 00308 { 00309 return SPLT_TRUE; 00310 } 00311 #endif 00312 } 00313 00314 if (state != NULL) 00315 { 00316 splt_e_set_strerror_msg_with_data(state, fname); 00317 } 00318 00319 return SPLT_FALSE; 00320 } 00321 00322 int splt_io_get_word(FILE *in, off_t offset, int mode, unsigned long *headw) 00323 { 00324 int i; 00325 *headw = 0; 00326 00327 if (fseeko(in, offset, mode)==-1) 00328 { 00329 return -1; 00330 } 00331 00332 for (i=0; i<4; i++) 00333 { 00334 if (feof(in)) 00335 { 00336 return -1; 00337 } 00338 *headw = *headw << 8; 00339 *headw |= fgetc(in); 00340 } 00341 00342 return 0; 00343 } 00344 00345 off_t splt_io_get_file_length(splt_state *state, FILE *in, const char *filename, int *error) 00346 { 00347 struct stat info; 00348 if (fstat(fileno(in), &info)==-1) 00349 { 00350 splt_e_set_strerror_msg_with_data(state, filename); 00351 *error = SPLT_ERROR_CANNOT_OPEN_FILE; 00352 return -1; 00353 } 00354 return info.st_size; 00355 } 00356 00357 void splt_io_create_output_dirs_if_necessary(splt_state *state, 00358 const char *output_filename, int *error) 00359 { 00360 if (splt_o_get_int_option(state, SPLT_OPT_CREATE_DIRS_FROM_FILENAMES)) 00361 { 00362 char *only_dirs = strdup(output_filename); 00363 if (! only_dirs) 00364 { 00365 *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY; 00366 return; 00367 } 00368 00369 char *dir_char = strrchr(only_dirs, SPLT_DIRCHAR); 00370 if (dir_char != NULL) 00371 { 00372 *dir_char = '\0'; 00373 #ifdef __WIN32__ 00374 if (strlen(only_dirs) == 2 && only_dirs[1] == ':' && 00375 strlen(output_filename) > 3) 00376 { 00377 *dir_char = SPLT_DIRCHAR; 00378 *(dir_char+1) = '\0'; 00379 } 00380 #endif 00381 int err = splt_io_create_directories(state, only_dirs); 00382 if (err < 0) { *error = err; } 00383 } 00384 00385 free(only_dirs); 00386 only_dirs = NULL; 00387 } 00388 } 00389 00390 int splt_io_create_directories(splt_state *state, const char *dir) 00391 { 00392 int result = SPLT_OK; 00393 00394 if (dir == NULL || dir[0] == '\0') 00395 { 00396 return result; 00397 } 00398 00399 char *dir_to_create = malloc(sizeof(char) * (strlen(dir)+100)); 00400 if (!dir_to_create) 00401 { 00402 return SPLT_ERROR_CANNOT_ALLOCATE_MEMORY; 00403 } 00404 00405 splt_d_print_debug(state, "Starting to create directories for _%s_ ...\n", dir); 00406 00407 const char *ptr = dir; 00408 00409 #ifdef __WIN32__ 00410 int first_time = SPLT_TRUE; 00411 #endif 00412 00413 while ((ptr = strchr(ptr, SPLT_DIRCHAR)) != NULL) 00414 { 00415 //handle C:DIRCHAR on windows 00416 #ifdef __WIN32__ 00417 if (first_time && splt_w32_str_starts_with_drive_root_directory(dir)) 00418 { 00419 ptr++; 00420 first_time = SPLT_FALSE; 00421 continue; 00422 } 00423 first_time = SPLT_FALSE; 00424 #endif 00425 00426 strncpy(dir_to_create, dir, ptr-dir); 00427 dir_to_create[ptr-dir] = '\0'; 00428 00429 if (dir_to_create[0] != '\0') 00430 { 00431 splt_d_print_debug(state,"Checking if _%s_ is a directory ...\n", dir_to_create); 00432 00433 if (! splt_io_check_if_directory(dir_to_create)) 00434 { 00435 splt_d_print_debug(state,"Creating directory _%s_ ...\n", dir_to_create); 00436 00437 if ((splt_io_mkdir(state, dir_to_create)) == -1) 00438 { 00439 splt_e_set_strerror_msg_with_data(state, dir_to_create); 00440 result = SPLT_ERROR_CANNOT_CREATE_DIRECTORY; 00441 goto end; 00442 } 00443 } 00444 } 00445 00446 ptr++; 00447 } 00448 00449 strncpy(dir_to_create, dir, strlen(dir) + 1); 00450 00451 if (! splt_io_check_if_directory(dir_to_create)) 00452 { 00453 splt_d_print_debug(state,"Creating final directory _%s_ ...\n", dir_to_create); 00454 00455 if ((splt_io_mkdir(state, dir_to_create)) == -1) 00456 { 00457 splt_e_set_strerror_msg_with_data(state, dir_to_create); 00458 result = SPLT_ERROR_CANNOT_CREATE_DIRECTORY; 00459 } 00460 } 00461 00462 end: 00463 if (dir_to_create) 00464 { 00465 free(dir_to_create); 00466 dir_to_create = NULL; 00467 } 00468 00469 return result; 00470 } 00471 00472 FILE *splt_io_fopen(const char *filename, const char *mode) 00473 { 00474 #ifdef __WIN32__ 00475 if (splt_w32_check_if_encoding_is_utf8(filename)) 00476 { 00477 wchar_t *wfilename = splt_w32_utf8_to_utf16(filename); 00478 wchar_t *wmode = splt_w32_utf8_to_utf16(mode); 00479 00480 FILE *file = _wfopen(wfilename, wmode); 00481 00482 if (wfilename) 00483 { 00484 free(wfilename); 00485 wfilename = NULL; 00486 } 00487 00488 if (wmode) 00489 { 00490 free(wmode); 00491 wmode = NULL; 00492 } 00493 00494 return file; 00495 } 00496 else 00497 #endif 00498 { 00499 return fopen(filename, mode); 00500 } 00501 } 00502 00503 int splt_io_mkdir(splt_state *state, const char *path) 00504 { 00505 if (splt_o_get_int_option(state, SPLT_OPT_PRETEND_TO_SPLIT)) 00506 { 00507 return 0; 00508 } 00509 00510 #ifdef __WIN32__ 00511 if (splt_w32_check_if_encoding_is_utf8(path)) 00512 { 00513 wchar_t *wpath = splt_w32_utf8_to_utf16(path); 00514 00515 int ret = _wmkdir(wpath); 00516 00517 if (wpath) 00518 { 00519 free(wpath); 00520 wpath = NULL; 00521 } 00522 00523 return ret; 00524 } 00525 else 00526 { 00527 return mkdir(path); 00528 } 00529 #else 00530 return mkdir(path, 0755); 00531 #endif 00532 } 00533 00534 int splt_io_stat(const char *path, mode_t *st_mode, off_t *st_size) 00535 { 00536 #ifdef __WIN32__ 00537 if (splt_w32_check_if_encoding_is_utf8(path)) 00538 { 00539 struct _stat buf; 00540 wchar_t *wpath = splt_w32_utf8_to_utf16(path); 00541 00542 int ret = _wstat(wpath, &buf); 00543 00544 if (wpath) 00545 { 00546 free(wpath); 00547 wpath = NULL; 00548 } 00549 00550 if (st_mode != NULL) 00551 { 00552 *st_mode = buf.st_mode; 00553 } 00554 00555 if (st_size != NULL) 00556 { 00557 *st_size = buf.st_size; 00558 } 00559 00560 return ret; 00561 } 00562 else 00563 #endif 00564 { 00565 struct stat buf; 00566 00567 #ifdef __WIN32__ 00568 int ret = stat(path, &buf); 00569 #else 00570 int ret = lstat(path, &buf); 00571 #endif 00572 00573 if (st_mode != NULL) 00574 { 00575 *st_mode = buf.st_mode; 00576 } 00577 00578 if (st_size != NULL) 00579 { 00580 *st_size = buf.st_size; 00581 } 00582 00583 return ret; 00584 } 00585 } 00586 00587 void splt_io_find_filenames(splt_state *state, const char *directory, 00588 char ***found_files, int *number_of_found_files, int *error) 00589 { 00590 #ifdef __WIN32__ 00591 struct _wdirent **files = NULL; 00592 #else 00593 struct dirent **files = NULL; 00594 #endif 00595 00596 //TODO: handle scandir error 00597 #ifdef __WIN32__ 00598 int num_of_files = wscandir(directory, &files, NULL, walphasort); 00599 #else 00600 int num_of_files = scandir(directory, &files, NULL, alphasort); 00601 #endif 00602 00603 int new_number_of_files = num_of_files; 00604 00605 if (files == NULL) { return; } 00606 00607 while (new_number_of_files-- > 0) 00608 { 00609 #ifdef __WIN32__ 00610 char *fname = splt_w32_utf16_to_utf8(files[new_number_of_files]->d_name); 00611 #else 00612 char *fname = files[new_number_of_files]->d_name; 00613 #endif 00614 00615 int fname_size = strlen(fname); 00616 00617 if (*error >= 0) 00618 { 00619 int path_with_fname_size = fname_size + strlen(directory) + 2; 00620 char *path_with_fname = malloc(sizeof(char) * path_with_fname_size); 00621 if (path_with_fname == NULL) 00622 { 00623 *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY; 00624 free(files[new_number_of_files]); 00625 files[new_number_of_files] = NULL; 00626 continue; 00627 } 00628 00629 snprintf(path_with_fname, path_with_fname_size, "%s%c%s", directory, 00630 SPLT_DIRCHAR, fname); 00631 00632 if (splt_io_check_if_file(state, path_with_fname)) 00633 { 00634 if (splt_p_file_is_supported_by_plugins(state, fname)) 00635 { 00636 if (!(*found_files)) 00637 { 00638 (*found_files) = malloc(sizeof(char *)); 00639 } 00640 else 00641 { 00642 (*found_files) = realloc((*found_files), 00643 sizeof(char *) * ((*number_of_found_files) + 1)); 00644 } 00645 if (*found_files == NULL) 00646 { 00647 *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY; 00648 goto end; 00649 } 00650 00651 int fname_size = strlen(path_with_fname) + 1; 00652 (*found_files)[(*number_of_found_files)] = malloc(sizeof(char) * fname_size); 00653 if ((*found_files)[(*number_of_found_files)] == NULL) 00654 { 00655 *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY; 00656 goto end; 00657 } 00658 00659 memset((*found_files)[(*number_of_found_files)], '\0', fname_size); 00660 strncat((*found_files)[*(number_of_found_files)], path_with_fname, fname_size); 00661 (*number_of_found_files)++; 00662 } 00663 } 00664 else if (splt_io_check_if_directory(path_with_fname)) 00665 { 00666 if (! splt_u_fname_is_directory_parent(fname, fname_size)) 00667 { 00668 splt_io_find_filenames(state, path_with_fname, found_files, 00669 number_of_found_files, error); 00670 } 00671 } 00672 00673 end: 00674 if (path_with_fname) 00675 { 00676 free(path_with_fname); 00677 path_with_fname = NULL; 00678 } 00679 } 00680 00681 free(files[new_number_of_files]); 00682 files[new_number_of_files] = NULL; 00683 } 00684 00685 if (files) 00686 { 00687 free(files); 00688 files = NULL; 00689 } 00690 } 00691 00692 size_t splt_io_fwrite(splt_state *state, const void *ptr, 00693 size_t size, size_t nmemb, FILE *stream) 00694 { 00695 if (splt_o_get_int_option(state, SPLT_OPT_PRETEND_TO_SPLIT)) 00696 { 00697 return size * nmemb; 00698 } 00699 else 00700 { 00701 return fwrite(ptr, size, nmemb, stream); 00702 } 00703 } 00704 00705 char *splt_io_readline(FILE *stream, int *error) 00706 { 00707 if (feof(stream)) 00708 { 00709 return NULL; 00710 } 00711 00712 int err = SPLT_OK; 00713 int bufsize = 255; 00714 char *buffer = malloc(sizeof(char) * bufsize); 00715 buffer[0] = '\0'; 00716 00717 char *line = NULL; 00718 while (fgets(buffer, bufsize, stream) != NULL) 00719 { 00720 err = splt_su_append_str(&line, buffer, NULL); 00721 if (err < 0) { *error = err; break; } 00722 00723 if (line != NULL && line[strlen(line)-1] == '\n') 00724 { 00725 free(buffer); 00726 return line; 00727 } 00728 00729 buffer[0] = '\0'; 00730 } 00731 00732 free(buffer); 00733 00734 if (*error < 0) 00735 { 00736 free(line); 00737 return NULL; 00738 } 00739 00740 return line; 00741 } 00742 00743 unsigned char *splt_io_fread(FILE *file, int start, size_t size) 00744 { 00745 unsigned char *bytes = malloc(sizeof(unsigned char) * size); 00746 00747 if (! bytes) 00748 { 00749 return NULL; 00750 } 00751 00752 size_t bytes_read = fread(bytes, 1, size, file); 00753 00754 if (bytes_read != size) 00755 { 00756 if (bytes) 00757 { 00758 free(bytes); 00759 bytes = NULL; 00760 } 00761 00762 return NULL; 00763 } 00764 00765 return bytes; 00766 } 00767 00768 static int splt_u_fname_is_directory_parent(char *fname, int fname_size) 00769 { 00770 return ((fname_size == 1) && (strcmp(fname, ".") == 0)) || 00771 ((fname_size == 2) && (strcmp(fname, "..") == 0)); 00772 } 00773