libmp3splt
src/input_output.c
Go to the documentation of this file.
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