Move the root_menu() call out of tree.c.
[Rockbox.git] / uisimulator / common / io.c
blob3f7087876aa991a3d781633cddc5fa33797731f8
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Daniel Stenberg
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdarg.h>
24 #include <sys/stat.h>
25 #include <time.h>
26 #ifdef __FreeBSD__
27 #include <sys/param.h>
28 #include <sys/mount.h>
29 #elif defined(__APPLE__)
30 #include <sys/param.h>
31 #include <sys/mount.h>
32 #elif !defined(WIN32)
33 #include <sys/vfs.h>
34 #endif
36 #ifdef WIN32
37 #include <windows.h>
38 #endif
40 #ifndef _MSC_VER
41 #include <dirent.h>
42 #include <unistd.h>
43 #else
44 #include "dir-win32.h"
45 #endif
47 #define MAX_PATH 260
49 #include <fcntl.h>
51 #include "debug.h"
52 #include "config.h"
54 /* Windows (and potentially other OSes) distinguish binary and text files.
55 * Define a dummy for the others. */
56 #ifndef O_BINARY
57 #define O_BINARY 0
58 #endif
60 /* Unicode compatibility for win32 */
61 #if defined __MINGW32__
62 /* Rockbox unicode functions */
63 extern const unsigned char* utf8decode(const unsigned char *utf8,
64 unsigned short *ucs);
65 extern unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8);
67 /* Static buffers for the conversion results. This isn't thread safe,
68 * but it's sufficient for rockbox. */
69 static unsigned char convbuf1[3*MAX_PATH];
70 static unsigned char convbuf2[3*MAX_PATH];
72 static wchar_t* utf8_to_ucs2(const unsigned char *utf8, void *buffer)
74 wchar_t *ucs = buffer;
76 while (*utf8)
77 utf8 = utf8decode(utf8, ucs++);
79 *ucs = 0;
80 return buffer;
82 static unsigned char *ucs2_to_utf8(const wchar_t *ucs, unsigned char *buffer)
84 unsigned char *utf8 = buffer;
86 while (*ucs)
87 utf8 = utf8encode(*ucs++, utf8);
89 *utf8 = 0;
90 return buffer;
93 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
94 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
95 #define DIR_T _WDIR
96 #define DIRENT_T struct _wdirent
97 #define STAT_T struct _stat
98 extern int _wmkdir(const wchar_t*);
99 extern int _wrmdir(const wchar_t*);
100 #define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
101 #define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
102 #define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
103 #define READDIR(a) (_wreaddir)(a)
104 #define CLOSEDIR(a) (_wclosedir)(a)
105 #define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
106 #define OPEN(a,b,c) (_wopen)(UTF8_TO_OS(a),b,c)
107 #define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
108 #define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
110 #else /* !__MINGW32__ */
112 #define UTF8_TO_OS(a) (a)
113 #define OS_TO_UTF8(a) (a)
114 #define DIR_T DIR
115 #define DIRENT_T struct dirent
116 #define STAT_T struct stat
117 #define MKDIR(a,b) (mkdir)(a,b)
118 #define RMDIR(a) (rmdir)(a)
119 #define OPENDIR(a) (opendir)(a)
120 #define READDIR(a) (readdir)(a)
121 #define CLOSEDIR(a) (closedir)(a)
122 #define STAT(a,b) (stat)(a,b)
123 #define OPEN(a,b,c) (open)(a,b,c)
124 #define REMOVE(a) (remove)(a)
125 #define RENAME(a,b) (rename)(a,b)
127 #endif /* !__MINGW32__ */
130 #ifdef HAVE_DIRCACHE
131 void dircache_remove(const char *name);
132 void dircache_rename(const char *oldpath, const char *newpath);
133 #endif
135 #define SIMULATOR_ARCHOS_ROOT "archos"
137 struct sim_dirent {
138 unsigned char d_name[MAX_PATH];
139 int attribute;
140 long size;
141 long startcluster;
142 unsigned short wrtdate; /* Last write date */
143 unsigned short wrttime; /* Last write time */
146 struct dirstruct {
147 void *dir; /* actually a DIR* dir */
148 char *name;
149 } SIM_DIR;
151 struct mydir {
152 DIR_T *dir;
153 char *name;
156 typedef struct mydir MYDIR;
158 #if 1 /* maybe this needs disabling for MSVC... */
159 static unsigned int rockbox2sim(int opt)
161 int newopt = O_BINARY;
163 if(opt & 1)
164 newopt |= O_WRONLY;
165 if(opt & 2)
166 newopt |= O_RDWR;
167 if(opt & 4)
168 newopt |= O_CREAT;
169 if(opt & 8)
170 newopt |= O_APPEND;
171 if(opt & 0x10)
172 newopt |= O_TRUNC;
174 return newopt;
176 #endif
178 MYDIR *sim_opendir(const char *name)
180 char buffer[MAX_PATH]; /* sufficiently big */
181 DIR_T *dir;
183 #ifndef __PCTOOL__
184 if(name[0] == '/')
186 snprintf(buffer, sizeof(buffer), "%s%s", SIMULATOR_ARCHOS_ROOT, name);
187 dir=(DIR_T *)OPENDIR(buffer);
189 else
190 #endif
191 dir=(DIR_T *)OPENDIR(name);
193 if(dir) {
194 MYDIR *my = (MYDIR *)malloc(sizeof(MYDIR));
195 my->dir = dir;
196 my->name = (char *)strdup(name);
198 return my;
200 /* failed open, return NULL */
201 return (MYDIR *)0;
204 struct sim_dirent *sim_readdir(MYDIR *dir)
206 char buffer[512]; /* sufficiently big */
207 static struct sim_dirent secret;
208 STAT_T s;
209 DIRENT_T *x11 = READDIR(dir->dir);
210 struct tm* tm;
212 if(!x11)
213 return (struct sim_dirent *)0;
215 strcpy((char *)secret.d_name, OS_TO_UTF8(x11->d_name));
217 /* build file name */
218 #ifdef __PCTOOL__
219 snprintf(buffer, sizeof(buffer), "%s/%s", dir->name, secret.d_name);
220 #else
221 snprintf(buffer, sizeof(buffer), SIMULATOR_ARCHOS_ROOT "%s/%s",
222 dir->name, secret.d_name);
223 #endif
224 STAT(buffer, &s); /* get info */
226 #define ATTR_DIRECTORY 0x10
228 secret.attribute = S_ISDIR(s.st_mode)?ATTR_DIRECTORY:0;
229 secret.size = s.st_size;
231 tm = localtime(&(s.st_mtime));
232 secret.wrtdate = ((tm->tm_year - 80) << 9) |
233 ((tm->tm_mon + 1) << 5) |
234 tm->tm_mday;
235 secret.wrttime = (tm->tm_hour << 11) |
236 (tm->tm_min << 5) |
237 (tm->tm_sec >> 1);
238 return &secret;
241 void sim_closedir(MYDIR *dir)
243 free(dir->name);
244 CLOSEDIR(dir->dir);
246 free(dir);
249 int sim_open(const char *name, int o)
251 char buffer[MAX_PATH]; /* sufficiently big */
252 int opts = rockbox2sim(o);
254 #ifndef __PCTOOL__
255 if(name[0] == '/')
257 snprintf(buffer, sizeof(buffer), "%s%s", SIMULATOR_ARCHOS_ROOT, name);
259 debugf("We open the real file '%s'\n", buffer);
260 return OPEN(buffer, opts, 0666);
263 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n",
264 name);
265 return -1;
266 #else
267 return OPEN(name, opts, 0666);
268 #endif
272 int sim_creat(const char *name)
274 #ifndef __PCTOOL__
275 char buffer[MAX_PATH]; /* sufficiently big */
276 if(name[0] == '/')
278 snprintf(buffer, sizeof(buffer), "%s%s", SIMULATOR_ARCHOS_ROOT, name);
280 debugf("We create the real file '%s'\n", buffer);
281 return OPEN(buffer, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666);
283 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n", name);
284 return -1;
285 #else
286 return OPEN(name, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666);
287 #endif
290 int sim_mkdir(const char *name)
292 #ifdef __PCTOOL__
293 return MKDIR(name, 0777);
294 #else
295 char buffer[MAX_PATH]; /* sufficiently big */
297 snprintf(buffer, sizeof(buffer), "%s%s", SIMULATOR_ARCHOS_ROOT, name);
299 debugf("We create the real directory '%s'\n", buffer);
300 return MKDIR(buffer, 0777);
301 #endif
304 int sim_rmdir(const char *name)
306 #ifdef __PCTOOL__
307 return RMDIR(name);
308 #else
309 char buffer[MAX_PATH]; /* sufficiently big */
310 if(name[0] == '/')
312 snprintf(buffer, sizeof(buffer), "%s%s", SIMULATOR_ARCHOS_ROOT, name);
314 debugf("We remove the real directory '%s'\n", buffer);
315 return RMDIR(buffer);
317 return RMDIR(name);
318 #endif
321 int sim_remove(const char *name)
323 #ifdef __PCTOOL__
324 return REMOVE(name);
325 #else
326 char buffer[MAX_PATH]; /* sufficiently big */
328 #ifdef HAVE_DIRCACHE
329 dircache_remove(name);
330 #endif
332 if(name[0] == '/') {
333 snprintf(buffer, sizeof(buffer), "%s%s", SIMULATOR_ARCHOS_ROOT, name);
335 debugf("We remove the real file '%s'\n", buffer);
336 return REMOVE(buffer);
338 return REMOVE(name);
339 #endif
342 int sim_rename(const char *oldpath, const char* newpath)
344 #ifdef __PCTOOL__
345 return RENAME(oldpath, newpath);
346 #else
347 char buffer1[MAX_PATH];
348 char buffer2[MAX_PATH];
350 #ifdef HAVE_DIRCACHE
351 dircache_rename(oldpath, newpath);
352 #endif
354 if(oldpath[0] == '/') {
355 snprintf(buffer1, sizeof(buffer1), "%s%s", SIMULATOR_ARCHOS_ROOT,
356 oldpath);
357 snprintf(buffer2, sizeof(buffer2), "%s%s", SIMULATOR_ARCHOS_ROOT,
358 newpath);
360 debugf("We rename the real file '%s' to '%s'\n", buffer1, buffer2);
361 return RENAME(buffer1, buffer2);
363 return -1;
364 #endif
367 /* rockbox off_t may be different from system off_t */
368 long sim_lseek(int fildes, long offset, int whence)
370 return lseek(fildes, offset, whence);
373 long sim_filesize(int fd)
375 #ifdef WIN32
376 return _filelength(fd);
377 #else
378 struct stat buf;
380 if (!fstat(fd, &buf))
381 return buf.st_size;
382 else
383 return -1;
384 #endif
387 void fat_size(unsigned int* size, unsigned int* free)
389 #ifdef WIN32
390 long secperclus, bytespersec, free_clusters, num_clusters;
392 if (GetDiskFreeSpace(NULL, &secperclus, &bytespersec, &free_clusters,
393 &num_clusters)) {
394 if (size)
395 *size = num_clusters * secperclus / 2 * (bytespersec / 512);
396 if (free)
397 *free = free_clusters * secperclus / 2 * (bytespersec / 512);
399 #else
400 struct statfs fs;
402 if (!statfs(".", &fs)) {
403 DEBUGF("statfs: bsize=%d blocks=%ld free=%ld\n",
404 (int)fs.f_bsize, fs.f_blocks, fs.f_bfree);
405 if (size)
406 *size = fs.f_blocks * (fs.f_bsize / 1024);
407 if (free)
408 *free = fs.f_bfree * (fs.f_bsize / 1024);
410 #endif
411 else {
412 if (size)
413 *size = 0;
414 if (free)
415 *free = 0;
419 int sim_fsync(int fd)
421 #ifdef WIN32
422 return _commit(fd);
423 #else
424 return fsync(fd);
425 #endif
428 #ifdef WIN32
429 /* sim-win32 */
430 #define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
431 #define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
432 #define dlclose(_x_) FreeLibrary(_x_)
433 #else
434 /* sim-x11 */
435 #include <dlfcn.h>
436 #endif
438 #define TEMP_CODEC_FILE "archos/_temp_codec%d.dll"
440 void *sim_codec_load_ram(char* codecptr, int size,
441 void* ptr2, int bufwrap, void **pd)
443 void *hdr;
444 char path[MAX_PATH];
445 int fd;
446 int copy_n;
447 int codec_count;
448 #ifdef WIN32
449 char buf[MAX_PATH];
450 #endif
452 *pd = NULL;
454 /* We have to create the dynamic link library file from ram so we
455 can simulate the codec loading. With voice and crossfade,
456 multiple codecs may be loaded at the same time, so we need
457 to find an unused filename */
458 for (codec_count = 0; codec_count < 10; codec_count++)
460 snprintf(path, sizeof(path), TEMP_CODEC_FILE, codec_count);
462 fd = OPEN(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRWXU);
463 if (fd >= 0)
464 break; /* Created a file ok */
466 if (fd < 0)
468 DEBUGF("failed to open for write: %s\n", path);
469 return NULL;
472 if (bufwrap == 0)
473 bufwrap = size;
475 copy_n = bufwrap < size ? bufwrap : size;
476 if (write(fd, codecptr, copy_n) != copy_n) {
477 DEBUGF("write failed");
478 return NULL;
480 size -= copy_n;
481 if (size > 0) {
482 if (write(fd, ptr2, size) != size) {
483 DEBUGF("write failed [2]");
484 return NULL;
487 close(fd);
489 /* Now load the library. */
490 *pd = dlopen(path, RTLD_NOW);
491 if (*pd == NULL) {
492 DEBUGF("failed to load %s\n", path);
493 #ifdef WIN32
494 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
495 buf, sizeof buf, NULL);
496 DEBUGF("dlopen(%s): %s\n", path, buf);
497 #else
498 DEBUGF("dlopen(%s): %s\n", path, dlerror());
499 #endif
500 return NULL;
503 hdr = dlsym(*pd, "__header");
504 if (!hdr)
505 hdr = dlsym(*pd, "___header");
507 return hdr; /* maybe NULL if symbol not present */
510 void sim_codec_close(void *pd)
512 dlclose(pd);
515 void *sim_plugin_load(char *plugin, void **pd)
517 void *hdr;
518 char path[MAX_PATH];
519 #ifdef WIN32
520 char buf[MAX_PATH];
521 #endif
523 snprintf(path, sizeof(path), "archos%s", plugin);
525 *pd = NULL;
527 *pd = dlopen(path, RTLD_NOW);
528 if (*pd == NULL) {
529 DEBUGF("failed to load %s\n", plugin);
530 #ifdef WIN32
531 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
532 buf, sizeof(buf), NULL);
533 DEBUGF("dlopen(%s): %s\n", path, buf);
534 #else
535 DEBUGF("dlopen(%s): %s\n", path, dlerror());
536 #endif
537 return NULL;
540 hdr = dlsym(*pd, "__header");
541 if (!hdr)
542 hdr = dlsym(*pd, "___header");
544 return hdr; /* maybe NULL if symbol not present */
547 void sim_plugin_close(void *pd)
549 dlclose(pd);
552 #ifdef WIN32
553 static unsigned old_cp;
555 void debug_exit(void)
557 /* Reset console output codepage */
558 SetConsoleOutputCP(old_cp);
561 void debug_init(void)
563 old_cp = GetConsoleOutputCP();
564 /* Set console output codepage to UTF8. Only works
565 * correctly when the console uses a truetype font. */
566 SetConsoleOutputCP(65001);
567 atexit(debug_exit);
569 #else
570 void debug_init(void)
572 /* nothing to be done */
574 #endif
576 void debugf(const char *fmt, ...)
578 va_list ap;
579 va_start( ap, fmt );
580 vfprintf( stderr, fmt, ap );
581 va_end( ap );
584 void ldebugf(const char* file, int line, const char *fmt, ...)
586 va_list ap;
587 va_start( ap, fmt );
588 fprintf( stderr, "%s:%d ", file, line );
589 vfprintf( stderr, fmt, ap );
590 va_end( ap );
593 /* rockbox off_t may be different from system off_t */
594 int sim_ftruncate(int fd, long length)
596 #ifdef WIN32
597 return _chsize(fd, length);
598 #else
599 return ftruncate(fd, length);
600 #endif