1 // Compatibility file functions
2 
3 #include <libretro.h>
4 #include <externs.h>
5 #include <compat.h>
6 #include <ui/ui.h>
7 #include <utils.h>
8 #include <string.h>
9 
10 #include <fuse/roms/48.h>
11 #include <fuse/roms/128-0.h>
12 #include <fuse/roms/128-1.h>
13 #include <fuse/roms/plus2-0.h>
14 #include <fuse/roms/plus2-1.h>
15 #include <fuse/roms/plus3-0.h>
16 #include <fuse/roms/plus3-1.h>
17 #include <fuse/roms/plus3-2.h>
18 #include <fuse/roms/plus3-3.h>
19 #include <fuse/roms/plus3e-0.h>
20 #include <fuse/roms/plus3e-1.h>
21 #include <fuse/roms/plus3e-2.h>
22 #include <fuse/roms/plus3e-3.h>
23 #include <fuse/roms/se-0.h>
24 #include <fuse/roms/se-1.h>
25 #include <fuse/roms/tc2048.h>
26 #include <fuse/roms/tc2068-0.h>
27 #include <fuse/roms/tc2068-1.h>
28 
29 #include <fuse/lib/compressed/tape_16.h>
30 #include <fuse/lib/compressed/tape_48.h>
31 #include <fuse/lib/compressed/tape_48_ntsc.h>
32 #include <fuse/lib/compressed/tape_128.h>
33 #include <fuse/lib/compressed/tape_plus2.h>
34 #include <fuse/lib/compressed/tape_plus2a.h>
35 #include <fuse/lib/compressed/tape_plus3.h>
36 #include <fuse/lib/compressed/tape_plus3e.h>
37 #include <fuse/lib/compressed/tape_se.h>
38 #include <fuse/lib/compressed/tape_2048.h>
39 #include <fuse/lib/compressed/tape_2068.h>
40 #include <fuse/lib/compressed/tape_ts2068.h>
41 #include <fuse/lib/compressed/tape_pentagon.h>
42 #include <fuse/lib/compressed/tape_scorpion.h>
43 
44 /* 4096 ought to be enough for anybody */
45 #define MAX_PATH_LEN 4096
46 
47 typedef struct
48 {
49    const char *name;
50    const unsigned char* ptr;
51    size_t size;
52 }
53 entry_t;
54 
55 static const entry_t mem_entries[] = {
56    { "48.rom",           fuse_roms_48_rom,                       sizeof(fuse_roms_48_rom) },
57    { "128-0.rom",        fuse_roms_128_0_rom,                    sizeof(fuse_roms_128_0_rom) },
58    { "128-1.rom",        fuse_roms_128_1_rom,                    sizeof(fuse_roms_128_1_rom) },
59    { "plus2-0.rom",      fuse_roms_plus2_0_rom,                  sizeof(fuse_roms_plus2_0_rom) },
60    { "plus2-1.rom",      fuse_roms_plus2_1_rom,                  sizeof(fuse_roms_plus2_1_rom) },
61    { "plus3-0.rom",      fuse_roms_plus3_0_rom,                  sizeof(fuse_roms_plus3_0_rom) },
62    { "plus3-1.rom",      fuse_roms_plus3_1_rom,                  sizeof(fuse_roms_plus3_1_rom) },
63    { "plus3-2.rom",      fuse_roms_plus3_2_rom,                  sizeof(fuse_roms_plus3_2_rom) },
64    { "plus3-3.rom",      fuse_roms_plus3_3_rom,                  sizeof(fuse_roms_plus3_3_rom) },
65    { "plus3e-0.rom",     fuse_roms_plus3e_0_rom,                 sizeof(fuse_roms_plus3e_0_rom) },
66    { "plus3e-1.rom",     fuse_roms_plus3e_1_rom,                 sizeof(fuse_roms_plus3e_1_rom) },
67    { "plus3e-2.rom",     fuse_roms_plus3e_2_rom,                 sizeof(fuse_roms_plus3e_2_rom) },
68    { "plus3e-3.rom",     fuse_roms_plus3e_3_rom,                 sizeof(fuse_roms_plus3e_3_rom) },
69    { "se-0.rom",         fuse_roms_se_0_rom,                     sizeof(fuse_roms_se_0_rom) },
70    { "se-1.rom",         fuse_roms_se_1_rom,                     sizeof(fuse_roms_se_1_rom) },
71    { "tc2048.rom",       fuse_roms_tc2048_rom,                   sizeof(fuse_roms_tc2048_rom) },
72    { "tc2068-0.rom",     fuse_roms_tc2068_0_rom,                 sizeof(fuse_roms_tc2068_0_rom) },
73    { "tc2068-1.rom",     fuse_roms_tc2068_1_rom,                 sizeof(fuse_roms_tc2068_1_rom) },
74 
75    { "tape_16.szx",       fuse_lib_compressed_tape_16_szx,       sizeof(fuse_lib_compressed_tape_16_szx) },
76    { "tape_48.szx",       fuse_lib_compressed_tape_48_szx,       sizeof(fuse_lib_compressed_tape_48_szx) },
77    { "tape_48_ntsc.szx",  fuse_lib_compressed_tape_48_ntsc_szx,  sizeof(fuse_lib_compressed_tape_48_ntsc_szx) },
78    { "tape_128.szx",      fuse_lib_compressed_tape_128_szx,      sizeof(fuse_lib_compressed_tape_128_szx) },
79    { "tape_plus2.szx",    fuse_lib_compressed_tape_plus2_szx,    sizeof(fuse_lib_compressed_tape_plus2_szx) },
80    { "tape_plus2a.szx",   fuse_lib_compressed_tape_plus2a_szx,   sizeof(fuse_lib_compressed_tape_plus2a_szx) },
81    { "tape_plus3.szx",    fuse_lib_compressed_tape_plus3_szx,    sizeof(fuse_lib_compressed_tape_plus3_szx) },
82    { "tape_plus3e.szx",   fuse_lib_compressed_tape_plus3e_szx,   sizeof(fuse_lib_compressed_tape_plus3e_szx) },
83    { "tape_se.szx",       fuse_lib_compressed_tape_se_szx,       sizeof(fuse_lib_compressed_tape_se_szx) },
84    { "tape_2048.szx",     fuse_lib_compressed_tape_2048_szx,     sizeof(fuse_lib_compressed_tape_2048_szx) },
85    { "tape_2068.szx",     fuse_lib_compressed_tape_2068_szx,     sizeof(fuse_lib_compressed_tape_2068_szx) },
86    { "tape_ts2068.szx",   fuse_lib_compressed_tape_ts2068_szx,   sizeof(fuse_lib_compressed_tape_ts2068_szx) },
87    { "tape_pentagon.szx", fuse_lib_compressed_tape_pentagon_szx, sizeof(fuse_lib_compressed_tape_pentagon_szx) },
88    { "tape_scorpion.szx", fuse_lib_compressed_tape_scorpion_szx, sizeof(fuse_lib_compressed_tape_scorpion_szx) },
89 };
90 
find_entry(const char * path)91 static const entry_t* find_entry(const char *path)
92 {
93    static entry_t tape;
94 
95    int i;
96    size_t len = strlen(path);
97 
98    // * signals us to load the tape data
99    if (path[0] == '*')
100    {
101       tape.name = NULL;
102       tape.ptr = (const unsigned char*)tape_data;
103       tape.size = tape_size;
104       return &tape;
105    }
106 
107    for (i = 0; i < sizeof(mem_entries) / sizeof(mem_entries[0]); i++)
108    {
109       size_t len2 = strlen(mem_entries[i].name);
110 
111       if (!strcmp(path + len - len2, mem_entries[i].name))
112       {
113          return mem_entries + i;
114       }
115    }
116 
117    return NULL;
118 }
119 
120 typedef struct
121 {
122    const char* ptr;
123    size_t length, remain;
124 }
125 compat_fd_internal;
126 
127 const compat_fd COMPAT_FILE_OPEN_FAILED = NULL;
128 
compat_file_open(const char * path,int write)129 compat_fd compat_file_open(const char *path, int write)
130 {
131    if (write)
132    {
133       log_cb(RETRO_LOG_ERROR, "Cannot open \"%s\" for writing\n", path);
134       return COMPAT_FILE_OPEN_FAILED;
135    }
136 
137    compat_fd_internal *fd = (compat_fd_internal*)malloc(sizeof(compat_fd_internal));
138 
139    if (!fd)
140    {
141       log_cb(RETRO_LOG_ERROR, "Out of memory while opening \"%s\"\n", path);
142       return COMPAT_FILE_OPEN_FAILED;
143    }
144 
145    const entry_t* entry = find_entry(path);
146 
147    if (entry != NULL)
148    {
149       fd->ptr = (const char*)entry->ptr;
150       fd->length = fd->remain = entry->size;
151 
152       log_cb(RETRO_LOG_INFO, "Opened \"%s\" from memory\n", path);
153       return (compat_fd)fd;
154    }
155 
156    log_cb(RETRO_LOG_INFO, "Could not find file \"%s\", trying file system\n", path);
157 
158    const char *sys;
159 
160    if (!env_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &sys) || !sys)
161    {
162       log_cb(RETRO_LOG_ERROR, "Error getting the system folder while opening \"%s\"\n", path);
163       free(fd);
164       return COMPAT_FILE_OPEN_FAILED;
165    }
166 
167    char system[MAX_PATH_LEN];
168    strncpy(system, sys, MAX_PATH_LEN);
169    system[MAX_PATH_LEN - 1] = 0;
170 
171    strncat(system, "/fuse", MAX_PATH_LEN);
172    system[MAX_PATH_LEN - 1] = 0;
173 
174    strncat(system, path, MAX_PATH_LEN);
175    system[MAX_PATH_LEN - 1] = 0;
176 
177    log_cb(RETRO_LOG_INFO, "Trying to open \"%s\" from the file system\n", system);
178    FILE* file = fopen(system, "rb");
179 
180    if (!file)
181    {
182       log_cb(RETRO_LOG_ERROR, "Could not find file \"%s\" on the file system\n", system);
183       free(fd);
184       return COMPAT_FILE_OPEN_FAILED;
185    }
186 
187    long size;
188 
189    if (fseek(file, 0, SEEK_END) != 0 || (size = ftell(file)) < 0 || fseek(file, 0, SEEK_SET) != 0)
190    {
191       log_cb(RETRO_LOG_ERROR, "Could not determine size of \"%s\"\n", system);
192       fclose(file);
193       free(fd);
194       return COMPAT_FILE_OPEN_FAILED;
195    }
196 
197    void* ptr = malloc(size);
198 
199    if (!ptr)
200    {
201       log_cb(RETRO_LOG_ERROR, "Out of memory while opening \"%s\"\n", system);
202       fclose(file);
203       free(fd);
204       return COMPAT_FILE_OPEN_FAILED;
205    }
206 
207    if (fread(ptr, 1, size, file) != size)
208    {
209       log_cb(RETRO_LOG_ERROR, "Error reading from \"%s\"\n", system);
210       free(ptr);
211       fclose(file);
212       free(fd);
213       return COMPAT_FILE_OPEN_FAILED;
214    }
215 
216    fclose(file);
217 
218    fd->ptr = (const char*)ptr;
219    fd->length = fd->remain = size;
220 
221    log_cb(RETRO_LOG_INFO, "Opened \"%s\" from the file system\n", system);
222    return (compat_fd)fd;
223 }
224 
compat_file_get_length(compat_fd cfd)225 off_t compat_file_get_length(compat_fd cfd)
226 {
227    compat_fd_internal *fd = (compat_fd_internal*)cfd;
228    return (off_t)fd->length;
229 }
230 
compat_file_read(compat_fd cfd,utils_file * file)231 int compat_file_read(compat_fd cfd, utils_file *file)
232 {
233    compat_fd_internal *fd = (compat_fd_internal*)cfd;
234    size_t numread;
235 
236    numread = file->length < fd->remain ? file->length : fd->remain;
237    memcpy(file->buffer, fd->ptr, numread);
238    fd->ptr += numread;
239    fd->remain -= numread;
240 
241    if (numread == file->length)
242    {
243       return 0;
244    }
245 
246    ui_error( UI_ERROR_ERROR,
247              "error reading file: expected %lu bytes, but read only %lu",
248              (unsigned long)file->length, (unsigned long)numread );
249    return 1;
250 }
251 
compat_file_write(compat_fd cfd,const unsigned char * buffer,size_t length)252 int compat_file_write(compat_fd cfd, const unsigned char *buffer, size_t length)
253 {
254    (void)cfd;
255    (void)buffer;
256    (void)length;
257    return 1;
258 }
259 
compat_file_close(compat_fd cfd)260 int compat_file_close(compat_fd cfd)
261 {
262    free(cfd);
263    return 0;
264 }
265 
compat_file_exists(const char * path)266 int compat_file_exists(const char *path)
267 {
268    log_cb(RETRO_LOG_INFO, "Checking if \"%s\" exists\n", path);
269 
270    int exists = 0;
271    compat_fd fd = compat_file_open(path, 0);
272 
273    if (fd != COMPAT_FILE_OPEN_FAILED)
274    {
275       compat_file_close(fd);
276       exists = 1;
277    }
278 
279    return exists;
280 }
281