1 /* Copyright (C) 2018
2 *
3 * Permission is hereby granted, free of charge,
4 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation the rights to
6 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
7 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8 *
9 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
14 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
15 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17 */
18
19 #include "retro_disk_control.h"
20 #include "retro_strings.h"
21 #include "retro_utils.h"
22 #include "file/file_path.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #define COMMENT "#"
29 #define M3U_SPECIAL_COMMAND "#COMMAND:"
30
31 // Return the directory name of 'filename' without trailing separator.
32 // Allocates returned string.
dirname_int(const char * filename)33 static char* dirname_int(const char* filename)
34 {
35 if (filename == NULL)
36 return NULL;
37
38 // Find last separator
39 char* right = find_last_slash(filename);
40 if (right)
41 return strleft(filename, right - filename);
42
43 // Not found
44 return NULL;
45 }
46
m3u_search_file(const char * basedir,const char * dskName)47 char* m3u_search_file(const char* basedir, const char* dskName)
48 {
49 // If basedir was provided
50 if(basedir != NULL && !path_is_absolute(dskName))
51 {
52 // Join basedir and dskName
53 char* dskPath = path_join_dup(basedir, dskName);
54
55 // Verify if this item is a relative filename (append it to the m3u path)
56 if (file_exists(dskPath))
57 {
58 // Return
59 return dskPath;
60 }
61 free(dskPath);
62 }
63
64 // Verify if this item is an absolute pathname (or the file is in working dir)
65 if (file_exists(dskName))
66 {
67 // Copy and return
68 return strdup(dskName);
69 }
70
71 // File not found
72 return NULL;
73 }
74
dc_reset(dc_storage * dc)75 void dc_reset(dc_storage* dc)
76 {
77 unsigned i;
78
79 // Verify
80 if(dc == NULL)
81 return;
82
83 // Clean the command
84 if(dc->command)
85 {
86 free(dc->command);
87 dc->command = NULL;
88 }
89
90 // Clean the struct
91 for(i=0; i < dc->count; i++)
92 {
93 free(dc->files[i]);
94 dc->files[i] = NULL;
95 free(dc->names[i]);
96 dc->names[i] = NULL;
97
98 dc->types[i] = DC_IMAGE_TYPE_NONE;
99 }
100
101 dc->unit = 0;
102 dc->count = 0;
103 dc->index = 0;
104 dc->eject_state = true;
105 }
106
dc_create(void)107 dc_storage* dc_create(void)
108 {
109 int i;
110
111 // Initialize the struct
112 dc_storage* dc = NULL;
113
114 if((dc = (dc_storage*) malloc(sizeof(dc_storage))) != NULL)
115 {
116 dc->count = 0;
117 dc->index = -1;
118 dc->eject_state = true;
119 dc->command = NULL;
120 for(i = 0; i < DC_MAX_SIZE; i++)
121 {
122 dc->files[i] = NULL;
123 dc->names[i] = NULL;
124 dc->types[i] = DC_IMAGE_TYPE_NONE;
125 }
126 }
127
128 return dc;
129 }
130
dc_add_file_int(dc_storage * dc,char * filename,char * name)131 bool dc_add_file_int(dc_storage* dc, char* filename, char* name)
132 {
133 // Verify
134 if (filename == NULL || dc == NULL || dc->count > DC_MAX_SIZE)
135 {
136 free(filename);
137 free(name);
138
139 return false;
140 }
141
142 // Add the file
143 dc->count++;
144 dc->files[dc->count-1] = filename;
145 dc->names[dc->count-1] = name;
146 dc->types[dc->count-1] = dc_get_image_type(filename);
147
148 printf(">>> dc added int %s - %s\n", filename, name);
149
150 return true;
151 }
152
dc_add_file(dc_storage * dc,const char * filename)153 bool dc_add_file(dc_storage* dc, const char* filename)
154 {
155 // Verify
156 if (dc == NULL || filename == NULL)
157 return false;
158
159 // Determine if tape or disk fliplist from first entry
160 if (dc->unit != -1)
161 {
162 if (dc_get_image_type(dc->files[0]) == DC_IMAGE_TYPE_TAPE)
163 dc->unit = DC_IMAGE_TYPE_TAPE;
164 else if (dc_get_image_type(dc->files[0]) == DC_IMAGE_TYPE_FLOPPY)
165 dc->unit = DC_IMAGE_TYPE_FLOPPY;
166 else
167 dc->unit = DC_IMAGE_TYPE_FLOPPY;
168 }
169
170 // Get 'name' - just the filename without extension
171 char tmp[512];
172 tmp[0] = '\0';
173 fill_short_pathname_representation(tmp, filename, sizeof(tmp));
174
175 printf(">>> dc added ext %s - %s\n", filename, tmp);
176
177 // Copy and return
178 return dc_add_file_int(dc, strdup(filename), strdup(tmp));
179 }
180
dc_remove_file(dc_storage * dc,int index)181 bool dc_remove_file(dc_storage* dc, int index)
182 {
183 if (dc == NULL)
184 return false;
185
186 if (index < 0 || index >= dc->count)
187 return false;
188
189 // "If ptr is a null pointer, no action occurs"
190 free(dc->files[index]);
191 dc->files[index] = NULL;
192 free(dc->names[index]);
193 dc->names[index] = NULL;
194
195 // Shift all entries after index one slot up
196 if (index != dc->count - 1)
197 {
198 memmove(dc->files + index, dc->files + index + 1, (dc->count - 1 - index) * sizeof(dc->files[0]));
199 memmove(dc->names + index, dc->names + index + 1, (dc->count - 1 - index) * sizeof(dc->names[0]));
200 }
201 dc->count--;
202
203 // Reset fliplist unit after removing last entry
204 if (dc->count == 0)
205 {
206 dc->unit = 0;
207 }
208 return true;
209 }
210
dc_parse_m3u(dc_storage * dc,const char * m3u_file)211 void dc_parse_m3u(dc_storage* dc, const char* m3u_file)
212 {
213 // Verify
214 if(dc == NULL)
215 return;
216
217 if(m3u_file == NULL)
218 return;
219
220 FILE* fp = NULL;
221
222 // Try to open the file
223 if ((fp = fopen(m3u_file, "r")) == NULL)
224 return;
225
226 // Reset
227 dc_reset(dc);
228
229 // Get the m3u base dir for resolving relative path
230 char* basedir = dirname_int(m3u_file);
231
232 // Disk control interface 'name' for the following file
233 char* image_name = NULL;
234
235 // Read the lines while there is line to read and we have enough space
236 char buffer[2048];
237 while ((dc->count <= DC_MAX_SIZE) && (fgets(buffer, sizeof(buffer), fp) != NULL))
238 {
239 char* string = trimwhitespace(buffer);
240
241 // If it's a m3u special key or a file
242 if (strstartswith(string, M3U_SPECIAL_COMMAND))
243 {
244 dc->command = strright(string, strlen(string) - strlen(M3U_SPECIAL_COMMAND));
245 }
246 else if (!strstartswith(string, COMMENT))
247 {
248 // Search the file (absolute, relative to m3u)
249 char* filename;
250 if ((filename = m3u_search_file(basedir, string)) != NULL)
251 {
252
253 char tmp[512];
254 tmp[0] = '\0';
255
256 fill_short_pathname_representation(tmp, filename, sizeof(tmp));
257 image_name = strdup(tmp);
258
259 // Add the file to the struct
260 dc_add_file_int(dc, filename, image_name);
261 image_name = NULL;
262 }
263
264 }
265 }
266
267 // If basedir was provided
268 if(basedir != NULL)
269 free(basedir);
270
271 // Close the file
272 fclose(fp);
273
274 if (dc->count != 0)
275 {
276 if (dc_get_image_type(dc->files[0]) == DC_IMAGE_TYPE_TAPE)
277 dc->unit = DC_IMAGE_TYPE_TAPE;
278 else if (dc_get_image_type(dc->files[0]) == DC_IMAGE_TYPE_FLOPPY)
279 dc->unit = DC_IMAGE_TYPE_FLOPPY;
280 else
281 dc->unit = DC_IMAGE_TYPE_FLOPPY;
282
283 printf(">>> dc unit: %i\n", dc->unit);
284 }
285
286 }
287
dc_free(dc_storage * dc)288 void dc_free(dc_storage* dc)
289 {
290 // Clean the struct
291 dc_reset(dc);
292 free(dc);
293 dc = NULL;
294 return;
295 }
296
dc_get_image_type(const char * filename)297 enum dc_image_type dc_get_image_type(const char* filename)
298 {
299 // Missing file
300 if (!filename || (*filename == '\0'))
301 return DC_IMAGE_TYPE_NONE;
302
303 // Floppy image
304 if (strendswith(filename, "dsk"))
305 return DC_IMAGE_TYPE_FLOPPY;
306
307 // Tape image
308 if (strendswith(filename, "tap") ||
309 strendswith(filename, "cdt"))
310 return DC_IMAGE_TYPE_TAPE;
311
312 // Fallback
313 return DC_IMAGE_TYPE_UNKNOWN;
314 }