Change application selection in configure. Make android raaa compile.
[kugel-rb.git] / uisimulator / common / io.c
blobf6abc7260135a85fba06fca581e4d68268e64d90
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Daniel Stenberg
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <sys/stat.h>
27 #include <time.h>
29 #define HAVE_STATVFS (!defined(WIN32) && !defined(ANDROID))
31 #if HAVE_STATVFS
32 #include <sys/statvfs.h>
33 #endif
35 #ifdef WIN32
36 #include <windows.h>
37 #endif
39 #ifndef _MSC_VER
40 #include <dirent.h>
41 #include <unistd.h>
42 #else
43 #include "dir-win32.h"
44 #endif
46 #include <fcntl.h>
47 #ifdef HAVE_SDL
48 #include <SDL.h>
49 #include <SDL_thread.h>
50 #include "thread-sdl.h"
51 #else
52 #define sim_thread_unlock() NULL
53 #define sim_thread_lock(a)
54 #endif
55 #include "thread.h"
56 #include "kernel.h"
57 #include "debug.h"
58 #include "config.h"
59 #include "ata.h" /* for IF_MV2 et al. */
60 #include "rbpaths.h"
62 /* keep this in sync with file.h! */
63 #undef MAX_PATH /* this avoids problems when building simulator */
64 #define MAX_PATH 260
65 #define MAX_OPEN_FILES 11
67 /* Windows (and potentially other OSes) distinguish binary and text files.
68 * Define a dummy for the others. */
69 #ifndef O_BINARY
70 #define O_BINARY 0
71 #endif
73 /* Unicode compatibility for win32 */
74 #if defined __MINGW32__
75 /* Rockbox unicode functions */
76 extern const unsigned char* utf8decode(const unsigned char *utf8,
77 unsigned short *ucs);
78 extern unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8);
80 /* Static buffers for the conversion results. This isn't thread safe,
81 * but it's sufficient for rockbox. */
82 static unsigned char convbuf1[3*MAX_PATH];
83 static unsigned char convbuf2[3*MAX_PATH];
85 static wchar_t* utf8_to_ucs2(const unsigned char *utf8, void *buffer)
87 wchar_t *ucs = buffer;
89 while (*utf8)
90 utf8 = utf8decode(utf8, ucs++);
92 *ucs = 0;
93 return buffer;
95 static unsigned char *ucs2_to_utf8(const wchar_t *ucs, unsigned char *buffer)
97 unsigned char *utf8 = buffer;
99 while (*ucs)
100 utf8 = utf8encode(*ucs++, utf8);
102 *utf8 = 0;
103 return buffer;
106 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
107 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
108 #define DIR_T _WDIR
109 #define DIRENT_T struct _wdirent
110 #define STAT_T struct _stat
111 extern int _wmkdir(const wchar_t*);
112 extern int _wrmdir(const wchar_t*);
113 #define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
114 #define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
115 #define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
116 #define READDIR(a) (_wreaddir)(a)
117 #define CLOSEDIR(a) (_wclosedir)(a)
118 #define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
119 /* empty variable parameter list doesn't work for variadic macros,
120 * so pretend the second parameter is variable too */
121 #define OPEN(a,...) (_wopen)(UTF8_TO_OS(a), __VA_ARGS__)
122 #define CLOSE(a) (close)(a)
123 #define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
124 #define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
126 #else /* !__MINGW32__ */
128 #define UTF8_TO_OS(a) (a)
129 #define OS_TO_UTF8(a) (a)
130 #define DIR_T DIR
131 #define DIRENT_T struct dirent
132 #define STAT_T struct stat
133 #define MKDIR(a,b) (mkdir)(a,b)
134 #define RMDIR(a) (rmdir)(a)
135 #define OPENDIR(a) (opendir)(a)
136 #define READDIR(a) (readdir)(a)
137 #define CLOSEDIR(a) (closedir)(a)
138 #define STAT(a,b) (stat)(a,b)
139 /* empty variable parameter list doesn't work for variadic macros,
140 * so pretend the second parameter is variable too */
141 #define OPEN(a, ...) (open)(a, __VA_ARGS__)
142 #define CLOSE(x) (close)(x)
143 #define REMOVE(a) (remove)(a)
144 #define RENAME(a,b) (rename)(a,b)
146 #endif /* !__MINGW32__ */
149 #ifdef HAVE_DIRCACHE
150 void dircache_remove(const char *name);
151 void dircache_rename(const char *oldname, const char *newname);
152 #endif
155 #define SIMULATOR_DEFAULT_ROOT "simdisk"
156 extern const char *sim_root_dir;
158 static int num_openfiles = 0;
160 struct sim_dirent {
161 unsigned char d_name[MAX_PATH];
162 int attribute;
163 long size;
164 long startcluster;
165 unsigned short wrtdate; /* Last write date */
166 unsigned short wrttime; /* Last write time */
169 struct dirstruct {
170 void *dir; /* actually a DIR* dir */
171 char *name;
172 } SIM_DIR;
174 struct mydir {
175 DIR_T *dir;
176 char *name;
179 typedef struct mydir MYDIR;
181 #if 1 /* maybe this needs disabling for MSVC... */
182 static unsigned int rockbox2sim(int opt)
184 int newopt = O_BINARY;
186 if(opt & 1)
187 newopt |= O_WRONLY;
188 if(opt & 2)
189 newopt |= O_RDWR;
190 if(opt & 4)
191 newopt |= O_CREAT;
192 if(opt & 8)
193 newopt |= O_APPEND;
194 if(opt & 0x10)
195 newopt |= O_TRUNC;
197 return newopt;
199 #endif
201 /** Simulator I/O engine routines **/
202 #define IO_YIELD_THRESHOLD 512
204 enum io_dir
206 IO_READ,
207 IO_WRITE,
210 struct sim_io
212 struct mutex sim_mutex; /* Rockbox mutex */
213 int cmd; /* The command to perform */
214 int ready; /* I/O ready flag - 1= ready */
215 int fd; /* The file to read/write */
216 void *buf; /* The buffer to read/write */
217 size_t count; /* Number of bytes to read/write */
218 size_t accum; /* Acculated bytes transferred */
221 static struct sim_io io;
223 int ata_init(void)
225 /* Initialize the rockbox kernel objects on a rockbox thread */
226 mutex_init(&io.sim_mutex);
227 io.accum = 0;
228 return 1;
231 int ata_spinup_time(void)
233 return HZ;
236 static ssize_t io_trigger_and_wait(enum io_dir cmd)
238 void *mythread = NULL;
239 ssize_t result;
241 if (io.count > IO_YIELD_THRESHOLD ||
242 (io.accum += io.count) >= IO_YIELD_THRESHOLD)
244 /* Allow other rockbox threads to run */
245 io.accum = 0;
246 mythread = sim_thread_unlock();
249 switch (cmd)
251 case IO_READ:
252 result = read(io.fd, io.buf, io.count);
253 break;
254 case IO_WRITE:
255 result = write(io.fd, io.buf, io.count);
256 break;
259 /* Regain our status as current */
260 if (mythread != NULL)
262 sim_thread_lock(mythread);
265 return result;
268 #if !defined(__PCTOOL__) && !defined(APPLICATION)
269 static const char *get_sim_pathname(const char *name)
271 static char buffer[MAX_PATH]; /* sufficiently big */
273 if(name[0] == '/')
275 snprintf(buffer, sizeof(buffer), "%s%s",
276 sim_root_dir != NULL ? sim_root_dir : SIMULATOR_DEFAULT_ROOT, name);
277 return buffer;
279 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n", name);
280 return name;
282 #else
283 #define get_sim_pathname(name) name
284 #endif
286 MYDIR *sim_opendir(const char *name)
288 DIR_T *dir;
290 dir = (DIR_T *) OPENDIR(get_sim_pathname(name));
292 if (dir)
294 MYDIR *my = (MYDIR *)malloc(sizeof(MYDIR));
295 my->dir = dir;
296 my->name = (char *)malloc(strlen(name)+1);
297 strcpy(my->name, name);
299 return my;
301 /* failed open, return NULL */
302 return (MYDIR *)0;
305 struct sim_dirent *sim_readdir(MYDIR *dir)
307 char buffer[MAX_PATH]; /* sufficiently big */
308 static struct sim_dirent secret;
309 STAT_T s;
310 DIRENT_T *x11 = READDIR(dir->dir);
311 struct tm* tm;
313 if(!x11)
314 return (struct sim_dirent *)0;
316 strcpy((char *)secret.d_name, OS_TO_UTF8(x11->d_name));
318 /* build file name */
319 snprintf(buffer, sizeof(buffer), "%s/%s",
320 get_sim_pathname(dir->name), secret.d_name);
321 STAT(buffer, &s); /* get info */
323 #define ATTR_DIRECTORY 0x10
325 secret.attribute = S_ISDIR(s.st_mode)?ATTR_DIRECTORY:0;
326 secret.size = s.st_size;
328 tm = localtime(&(s.st_mtime));
329 secret.wrtdate = ((tm->tm_year - 80) << 9) |
330 ((tm->tm_mon + 1) << 5) |
331 tm->tm_mday;
332 secret.wrttime = (tm->tm_hour << 11) |
333 (tm->tm_min << 5) |
334 (tm->tm_sec >> 1);
335 return &secret;
338 void sim_closedir(MYDIR *dir)
340 free(dir->name);
341 CLOSEDIR(dir->dir);
343 free(dir);
346 int sim_open(const char *name, int o, ...)
348 int opts = rockbox2sim(o);
349 int ret;
350 if (num_openfiles >= MAX_OPEN_FILES)
351 return -2;
353 if (opts & O_CREAT)
355 va_list ap;
356 va_start(ap, o);
357 mode_t mode = va_arg(ap, unsigned int);
358 ret = OPEN(get_sim_pathname(name), opts, mode);
359 va_end(ap);
361 else
362 ret = OPEN(get_sim_pathname(name), opts);
364 if (ret >= 0)
365 num_openfiles++;
366 return ret;
369 int sim_close(int fd)
371 int ret;
372 ret = CLOSE(fd);
373 if (ret == 0)
374 num_openfiles--;
375 return ret;
378 int sim_creat(const char *name, mode_t mode)
380 return OPEN(get_sim_pathname(name), O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, mode);
383 ssize_t sim_read(int fd, void *buf, size_t count)
385 ssize_t result;
387 mutex_lock(&io.sim_mutex);
389 /* Setup parameters */
390 io.fd = fd;
391 io.buf = buf;
392 io.count = count;
394 result = io_trigger_and_wait(IO_READ);
396 mutex_unlock(&io.sim_mutex);
398 return result;
401 ssize_t sim_write(int fd, const void *buf, size_t count)
403 ssize_t result;
405 mutex_lock(&io.sim_mutex);
407 io.fd = fd;
408 io.buf = (void*)buf;
409 io.count = count;
411 result = io_trigger_and_wait(IO_WRITE);
413 mutex_unlock(&io.sim_mutex);
415 return result;
418 int sim_mkdir(const char *name)
420 return MKDIR(get_sim_pathname(name), 0777);
423 int sim_rmdir(const char *name)
425 return RMDIR(get_sim_pathname(name));
428 int sim_remove(const char *name)
430 #ifdef HAVE_DIRCACHE
431 dircache_remove(name);
432 #endif
433 return REMOVE(get_sim_pathname(name));
436 int sim_rename(const char *oldname, const char *newname)
438 char sim_old[MAX_PATH];
439 char sim_new[MAX_PATH];
440 #ifdef HAVE_DIRCACHE
441 dircache_rename(oldname, newname);
442 #endif
443 // This is needed as get_sim_pathname() has a static buffer
444 strncpy(sim_old, get_sim_pathname(oldname), MAX_PATH);
445 strncpy(sim_new, get_sim_pathname(newname), MAX_PATH);
446 return RENAME(sim_old, sim_new);
449 /* rockbox off_t may be different from system off_t */
450 long sim_lseek(int fildes, long offset, int whence)
452 return lseek(fildes, offset, whence);
455 long sim_filesize(int fd)
457 #ifdef WIN32
458 return _filelength(fd);
459 #else
460 struct stat buf;
462 if (!fstat(fd, &buf))
463 return buf.st_size;
464 else
465 return -1;
466 #endif
469 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
471 #ifdef HAVE_MULTIVOLUME
472 if (volume != 0) {
473 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
475 if (size) *size = 0;
476 if (free) *free = 0;
477 return;
479 #endif
481 #ifdef WIN32
482 long secperclus, bytespersec, free_clusters, num_clusters;
484 if (GetDiskFreeSpace(NULL, &secperclus, &bytespersec, &free_clusters,
485 &num_clusters)) {
486 if (size)
487 *size = num_clusters * secperclus / 2 * (bytespersec / 512);
488 if (free)
489 *free = free_clusters * secperclus / 2 * (bytespersec / 512);
491 #elif HAVE_STATVFS
492 struct statvfs vfs;
494 if (!statvfs(".", &vfs)) {
495 DEBUGF("statvfs: frsize=%d blocks=%ld free=%ld\n",
496 (int)vfs.f_frsize, (long)vfs.f_blocks, (long)vfs.f_bfree);
497 if (size)
498 *size = vfs.f_blocks / 2 * (vfs.f_frsize / 512);
499 if (free)
500 *free = vfs.f_bfree / 2 * (vfs.f_frsize / 512);
501 } else
502 #endif
504 if (size)
505 *size = 0;
506 if (free)
507 *free = 0;
511 int sim_fsync(int fd)
513 #ifdef WIN32
514 return _commit(fd);
515 #else
516 return fsync(fd);
517 #endif
520 #ifdef WIN32
521 /* sim-win32 */
522 #define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
523 #define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
524 #define dlclose(_x_) FreeLibrary(_x_)
525 #else
526 /* sim-x11 */
527 #include <dlfcn.h>
528 #endif
530 void *sim_codec_load_ram(char* codecptr, int size, void **pd)
532 void *hdr;
533 char path[MAX_PATH];
534 int fd;
535 int codec_count;
536 #ifdef WIN32
537 char buf[MAX_PATH];
538 #endif
540 *pd = NULL;
542 /* We have to create the dynamic link library file from ram so we
543 can simulate the codec loading. With voice and crossfade,
544 multiple codecs may be loaded at the same time, so we need
545 to find an unused filename */
546 for (codec_count = 0; codec_count < 10; codec_count++)
548 char name[MAX_PATH];
549 const char *_name = get_user_file_path(ROCKBOX_DIR, 0, name, sizeof(name));
550 snprintf(path, sizeof(path), "%s/_temp_codec%d.dll", get_sim_pathname(_name), codec_count);
551 fd = OPEN(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRWXU);
552 if (fd >= 0)
553 break; /* Created a file ok */
555 if (fd < 0)
557 DEBUGF("failed to open for write: %s\n", path);
558 return NULL;
561 if (write(fd, codecptr, size) != size)
563 DEBUGF("write failed");
564 return NULL;
566 close(fd);
568 /* Now load the library. */
569 *pd = dlopen(path, RTLD_NOW);
570 if (*pd == NULL)
572 DEBUGF("failed to load %s\n", path);
573 #ifdef WIN32
574 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
575 buf, sizeof buf, NULL);
576 DEBUGF("dlopen(%s): %s\n", path, buf);
577 #else
578 DEBUGF("dlopen(%s): %s\n", path, dlerror());
579 #endif
580 return NULL;
583 hdr = dlsym(*pd, "__header");
584 if (!hdr)
585 hdr = dlsym(*pd, "___header");
587 return hdr; /* maybe NULL if symbol not present */
590 void sim_codec_close(void *pd)
592 dlclose(pd);
595 void *sim_plugin_load(char *plugin, void **pd)
597 void *hdr;
598 char path[MAX_PATH];
599 #ifdef WIN32
600 char buf[MAX_PATH];
601 #endif
603 snprintf(path, sizeof(path), "%s", get_sim_pathname(plugin));
605 *pd = NULL;
607 *pd = dlopen(path, RTLD_NOW);
608 if (*pd == NULL) {
609 DEBUGF("failed to load %s\n", plugin);
610 #ifdef WIN32
611 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
612 buf, sizeof(buf), NULL);
613 DEBUGF("dlopen(%s): %s\n", path, buf);
614 #else
615 DEBUGF("dlopen(%s): %s\n", path, dlerror());
616 #endif
617 return NULL;
620 hdr = dlsym(*pd, "__header");
621 if (!hdr)
622 hdr = dlsym(*pd, "___header");
624 return hdr; /* maybe NULL if symbol not present */
627 void sim_plugin_close(void *pd)
629 dlclose(pd);
632 #ifdef WIN32
633 static unsigned old_cp;
635 void debug_exit(void)
637 /* Reset console output codepage */
638 SetConsoleOutputCP(old_cp);
641 void debug_init(void)
643 old_cp = GetConsoleOutputCP();
644 /* Set console output codepage to UTF8. Only works
645 * correctly when the console uses a truetype font. */
646 SetConsoleOutputCP(65001);
647 atexit(debug_exit);
649 #else
650 void debug_init(void)
652 /* nothing to be done */
654 #endif
656 void debugf(const char *fmt, ...)
658 va_list ap;
659 va_start( ap, fmt );
660 vfprintf( stderr, fmt, ap );
661 va_end( ap );
664 void ldebugf(const char* file, int line, const char *fmt, ...)
666 va_list ap;
667 va_start( ap, fmt );
668 fprintf( stderr, "%s:%d ", file, line );
669 vfprintf( stderr, fmt, ap );
670 va_end( ap );
673 /* rockbox off_t may be different from system off_t */
674 int sim_ftruncate(int fd, long length)
676 #ifdef WIN32
677 return _chsize(fd, length);
678 #else
679 return ftruncate(fd, length);
680 #endif