1 /*
2  * This file is part of MPlayer.
3  *
4  * MPlayer is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * MPlayer is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 /**
20  * @file
21  * @brief Miscellaneous utilities
22  */
23 
24 #include <ctype.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "misc.h"
30 #include "string.h"
31 #include "gui/app/gui.h"
32 
33 #define CFG_OLD_PLAYLIST
34 #include "gui/app/cfg-old.c"
35 
36 #include "mp_msg.h"
37 
38 /**
39  * @brief Read characters from @a file.
40  *
41  * @param str memory location of a buffer to receive the read characters
42  * @param size number of characters read at the most (including a terminating null-character)
43  * @param file file to read from
44  *
45  * @return str (success) or NULL (error)
46  *
47  * @note Reading stops with an end-of-line character or at end of file.
48  */
fgetstr(char * str,int size,FILE * file)49 char *fgetstr(char *str, int size, FILE *file)
50 {
51     char *s;
52 
53     s = fgets(str, size, file);
54 
55     if (s)
56         s[strcspn(s, "\n\r")] = 0;
57 
58     return s;
59 }
60 
61 /**
62  * @brief Constrain a @a value to be in the range of 0 to 100.
63  *
64  * @param value value to be checked
65  *
66  * @return a value in the range of 0 to 100
67  */
constrain(float value)68 float constrain(float value)
69 {
70     if (value < 0.0f)
71         return 0.0f;
72     if (value > 100.0f)
73         return 100.0f;
74 
75     return value;
76 }
77 
78 /**
79  * @brief Convert MM:SS:FF (minute/second/frame) to seconds.
80  *
81  * @param msf string in MM:SS:FF format
82  *
83  * @return seconds equivalent to @a msf (0 in case of error)
84  */
msf2sec(const char * msf)85 float msf2sec(const char *msf)
86 {
87     int i;
88 
89     for (i = 0; i < 8; i++)
90         switch (i) {
91         case 0:
92         case 1:
93         case 3:
94         case 4:
95         case 6:
96         case 7:
97             if (!isdigit(msf[i]))
98                 return 0.0f;
99             break;
100 
101         case 2:
102         case 5:
103             if (msf[i] != ':')
104                 return 0.0f;
105             break;
106         }
107 
108     return (msf[0] - '0') * 600 + (msf[1] - '0') * 60 +
109            (msf[3] - '0') * 10 + (msf[4] - '0') +
110            ((msf[6] - '0') * 10 + (msf[7] - '0')) / 75.0f;
111 }
112 
113 /**
114  * @brief Analyze a cue file whether it describes a disc image (binary data)
115  *        or a playlist for data files containing multiple titles.
116  *
117  * @param fname cue file to be analyzed
118  *
119  * @return pointer to an array of playlist items or NULL (binary data or error)
120  */
cue_playlist(const char * fname)121 plItem **cue_playlist(const char *fname)
122 {
123     static plItem *item[101];
124     FILE *file;
125     char line[256], *l, *fmt, *path = NULL, *data = NULL;
126     int i = -1, isFILE = False, isTRACK = False;
127 
128     file = fopen(fname, "rt");
129 
130     if (file)
131         mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[misc] cue file: %s\n", fname);
132     else
133         return NULL;
134 
135     memset(item, 0, sizeof(item));
136 
137     while (fgetstr(line, sizeof(line), file) && (i < 99)) {
138         l = (char *)ltrim(line);
139 
140         if (strncmp(l, "FILE ", 5) == 0) {
141             fmt = strrchr(l, ' ');
142 
143             if (strcmp(fmt + 1, "BINARY") == 0) {
144                 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[misc] cue file describes BINARY (bin/cue)\n");
145                 break;
146             }
147 
148             *fmt = 0;
149 
150             setdup(&data, dequote(l + 5));
151             mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[misc] cue file data: %s (%s)\n", data, fmt + 1);
152 
153             if (strrchr(data, '/')) {
154                 setdup(&path, data);
155                 l  = strrchr(path, '/');
156                 *l = 0;
157                 setdup(&data, l + 1);
158             } else {
159                 setdup(&path, fname);
160                 l = strrchr(path, '/');
161 
162                 if (l)
163                     *l = 0;
164                 else
165                     setdup(&path, ".");
166             }
167 
168             isFILE = True;
169         } else if (strncmp(l, "TRACK ", 6) == 0) {
170             if (!isFILE)
171                 continue;
172 
173             item[++i] = calloc(1, sizeof(**item));
174 
175             if (!item[i])
176                 break;
177 
178             item[i]->path = strdup(cfg_old_filename_from_utf8(path));
179             item[i]->name = strdup(cfg_old_filename_from_utf8(data));
180 
181             isTRACK = True;
182         } else if (strncmp(l, "TITLE ", 6) == 0) {
183             if (!isTRACK)
184                 continue;
185 
186             item[i]->title = strdup(dequote(l + 6));
187         } else if (strncmp(l, "INDEX 01 ", 9) == 0) {
188             if (!isTRACK)
189                 continue;
190 
191             item[i]->start = msf2sec(l + 9);
192 
193             mp_msg(MSGT_GPLAYER, MSGL_V, "[misc] cue file data track %02d starts at %s\n", i + 1, l + 9);
194         }
195     }
196 
197     free(path);
198     free(data);
199     fclose(file);
200 
201     return (i == -1 ? NULL : item);
202 }
203