Moved database builder into a separate directory, and gave it its' own Makefile....
[kugel-rb.git] / uisimulator / common / io.c
blob185e46260c844a4afb566a2027b6531218f382a0
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>
28 #ifdef __FreeBSD__
29 #include <sys/param.h>
30 #include <sys/mount.h>
31 #elif defined(__APPLE__)
32 #include <sys/param.h>
33 #include <sys/mount.h>
34 #elif !defined(WIN32)
35 #include <sys/vfs.h>
36 #endif
38 #ifdef WIN32
39 #include <windows.h>
40 #endif
42 #ifndef _MSC_VER
43 #include <dirent.h>
44 #include <unistd.h>
45 #else
46 #include "dir-win32.h"
47 #endif
49 #define MAX_PATH 260
50 #define MAX_OPEN_FILES 11
52 #include <fcntl.h>
53 #include <SDL.h>
54 #include <SDL_thread.h>
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 "thread-sdl.h"
63 /* Windows (and potentially other OSes) distinguish binary and text files.
64 * Define a dummy for the others. */
65 #ifndef O_BINARY
66 #define O_BINARY 0
67 #endif
69 /* Unicode compatibility for win32 */
70 #if defined __MINGW32__
71 /* Rockbox unicode functions */
72 extern const unsigned char* utf8decode(const unsigned char *utf8,
73 unsigned short *ucs);
74 extern unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8);
76 /* Static buffers for the conversion results. This isn't thread safe,
77 * but it's sufficient for rockbox. */
78 static unsigned char convbuf1[3*MAX_PATH];
79 static unsigned char convbuf2[3*MAX_PATH];
81 static wchar_t* utf8_to_ucs2(const unsigned char *utf8, void *buffer)
83 wchar_t *ucs = buffer;
85 while (*utf8)
86 utf8 = utf8decode(utf8, ucs++);
88 *ucs = 0;
89 return buffer;
91 static unsigned char *ucs2_to_utf8(const wchar_t *ucs, unsigned char *buffer)
93 unsigned char *utf8 = buffer;
95 while (*ucs)
96 utf8 = utf8encode(*ucs++, utf8);
98 *utf8 = 0;
99 return buffer;
102 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
103 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
104 #define DIR_T _WDIR
105 #define DIRENT_T struct _wdirent
106 #define STAT_T struct _stat
107 extern int _wmkdir(const wchar_t*);
108 extern int _wrmdir(const wchar_t*);
109 #define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
110 #define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
111 #define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
112 #define READDIR(a) (_wreaddir)(a)
113 #define CLOSEDIR(a) (_wclosedir)(a)
114 #define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
115 #define OPEN(a,b,c) (_wopen)(UTF8_TO_OS(a),b,c)
116 #define CLOSE(a) (close)(a)
117 #define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
118 #define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
120 #else /* !__MINGW32__ */
122 #define UTF8_TO_OS(a) (a)
123 #define OS_TO_UTF8(a) (a)
124 #define DIR_T DIR
125 #define DIRENT_T struct dirent
126 #define STAT_T struct stat
127 #define MKDIR(a,b) (mkdir)(a,b)
128 #define RMDIR(a) (rmdir)(a)
129 #define OPENDIR(a) (opendir)(a)
130 #define READDIR(a) (readdir)(a)
131 #define CLOSEDIR(a) (closedir)(a)
132 #define STAT(a,b) (stat)(a,b)
133 #define OPEN(a,b,c) (open)(a,b,c)
134 #define CLOSE(x) (close)(x)
135 #define REMOVE(a) (remove)(a)
136 #define RENAME(a,b) (rename)(a,b)
138 #endif /* !__MINGW32__ */
141 #ifdef HAVE_DIRCACHE
142 void dircache_remove(const char *name);
143 void dircache_rename(const char *oldpath, const char *newpath);
144 #endif
147 #define SIMULATOR_DEFAULT_ROOT "simdisk"
148 extern const char *sim_root_dir;
150 static int num_openfiles = 0;
152 struct sim_dirent {
153 unsigned char d_name[MAX_PATH];
154 int attribute;
155 long size;
156 long startcluster;
157 unsigned short wrtdate; /* Last write date */
158 unsigned short wrttime; /* Last write time */
161 struct dirstruct {
162 void *dir; /* actually a DIR* dir */
163 char *name;
164 } SIM_DIR;
166 struct mydir {
167 DIR_T *dir;
168 char *name;
171 typedef struct mydir MYDIR;
173 #if 1 /* maybe this needs disabling for MSVC... */
174 static unsigned int rockbox2sim(int opt)
176 int newopt = O_BINARY;
178 if(opt & 1)
179 newopt |= O_WRONLY;
180 if(opt & 2)
181 newopt |= O_RDWR;
182 if(opt & 4)
183 newopt |= O_CREAT;
184 if(opt & 8)
185 newopt |= O_APPEND;
186 if(opt & 0x10)
187 newopt |= O_TRUNC;
189 return newopt;
191 #endif
193 /** Simulator I/O engine routines **/
194 #define IO_YIELD_THRESHOLD 512
196 enum
198 IO_READ,
199 IO_WRITE,
202 struct sim_io
204 struct mutex sim_mutex; /* Rockbox mutex */
205 int cmd; /* The command to perform */
206 int ready; /* I/O ready flag - 1= ready */
207 int fd; /* The file to read/write */
208 void *buf; /* The buffer to read/write */
209 size_t count; /* Number of bytes to read/write */
210 size_t accum; /* Acculated bytes transferred */
213 static struct sim_io io;
215 int ata_init(void)
217 /* Initialize the rockbox kernel objects on a rockbox thread */
218 mutex_init(&io.sim_mutex);
219 io.accum = 0;
220 return 1;
223 static ssize_t io_trigger_and_wait(int cmd)
225 void *mythread = NULL;
226 ssize_t result;
228 if (io.count > IO_YIELD_THRESHOLD ||
229 (io.accum += io.count) >= IO_YIELD_THRESHOLD)
231 /* Allow other rockbox threads to run */
232 io.accum = 0;
233 mythread = thread_sdl_thread_unlock();
236 switch (cmd)
238 case IO_READ:
239 result = read(io.fd, io.buf, io.count);
240 break;
241 case IO_WRITE:
242 result = write(io.fd, io.buf, io.count);
243 break;
246 /* Regain our status as current */
247 if (mythread != NULL)
249 thread_sdl_thread_lock(mythread);
252 return result;
255 #ifndef __PCTOOL__
256 static const char *get_sim_rootdir()
258 if (sim_root_dir != NULL)
259 return sim_root_dir;
260 return SIMULATOR_DEFAULT_ROOT;
262 #endif
264 MYDIR *sim_opendir(const char *name)
266 DIR_T *dir;
268 #ifndef __PCTOOL__
269 char buffer[MAX_PATH]; /* sufficiently big */
271 if(name[0] == '/')
273 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
274 dir=(DIR_T *)OPENDIR(buffer);
276 else
277 #endif
278 dir=(DIR_T *)OPENDIR(name);
280 if(dir) {
281 MYDIR *my = (MYDIR *)malloc(sizeof(MYDIR));
282 my->dir = dir;
283 my->name = (char *)malloc(strlen(name)+1);
284 strcpy(my->name, name);
286 return my;
288 /* failed open, return NULL */
289 return (MYDIR *)0;
292 struct sim_dirent *sim_readdir(MYDIR *dir)
294 char buffer[MAX_PATH]; /* sufficiently big */
295 static struct sim_dirent secret;
296 STAT_T s;
297 DIRENT_T *x11 = READDIR(dir->dir);
298 struct tm* tm;
300 if(!x11)
301 return (struct sim_dirent *)0;
303 strcpy((char *)secret.d_name, OS_TO_UTF8(x11->d_name));
305 /* build file name */
306 #ifdef __PCTOOL__
307 snprintf(buffer, sizeof(buffer), "%s/%s", dir->name, secret.d_name);
308 #else
309 snprintf(buffer, sizeof(buffer), "%s/%s/%s",
310 get_sim_rootdir(), dir->name, secret.d_name);
311 #endif
312 STAT(buffer, &s); /* get info */
314 #define ATTR_DIRECTORY 0x10
316 secret.attribute = S_ISDIR(s.st_mode)?ATTR_DIRECTORY:0;
317 secret.size = s.st_size;
319 tm = localtime(&(s.st_mtime));
320 secret.wrtdate = ((tm->tm_year - 80) << 9) |
321 ((tm->tm_mon + 1) << 5) |
322 tm->tm_mday;
323 secret.wrttime = (tm->tm_hour << 11) |
324 (tm->tm_min << 5) |
325 (tm->tm_sec >> 1);
326 return &secret;
329 void sim_closedir(MYDIR *dir)
331 free(dir->name);
332 CLOSEDIR(dir->dir);
334 free(dir);
337 int sim_open(const char *name, int o)
339 char buffer[MAX_PATH]; /* sufficiently big */
340 int opts = rockbox2sim(o);
341 int ret;
343 if (num_openfiles >= MAX_OPEN_FILES)
344 return -2;
346 #ifndef __PCTOOL__
347 if(name[0] == '/')
349 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
351 /* debugf("We open the real file '%s'\n", buffer); */
352 if (num_openfiles < MAX_OPEN_FILES)
354 ret = OPEN(buffer, opts, 0666);
355 if (ret >= 0) num_openfiles++;
356 return ret;
360 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n",
361 name);
362 return -1;
363 #else
364 ret = OPEN(name, opts, 0666);
365 if (ret >= 0)
366 num_openfiles++;
367 return ret;
368 #endif
371 int sim_close(int fd)
373 int ret;
374 ret = CLOSE(fd);
375 if (ret == 0) num_openfiles--;
376 return ret;
379 int sim_creat(const char *name)
381 #ifndef __PCTOOL__
382 char buffer[MAX_PATH]; /* sufficiently big */
383 if(name[0] == '/')
385 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
387 /* debugf("We create the real file '%s'\n", buffer); */
388 return OPEN(buffer, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666);
390 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n", name);
391 return -1;
392 #else
393 return OPEN(name, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666);
394 #endif
397 ssize_t sim_read(int fd, void *buf, size_t count)
399 ssize_t result;
401 mutex_lock(&io.sim_mutex);
403 /* Setup parameters */
404 io.fd = fd;
405 io.buf = buf;
406 io.count = count;
408 result = io_trigger_and_wait(IO_READ);
410 mutex_unlock(&io.sim_mutex);
412 return result;
415 ssize_t sim_write(int fd, const void *buf, size_t count)
417 ssize_t result;
419 mutex_lock(&io.sim_mutex);
421 io.fd = fd;
422 io.buf = (void*)buf;
423 io.count = count;
425 result = io_trigger_and_wait(IO_WRITE);
427 mutex_unlock(&io.sim_mutex);
429 return result;
432 int sim_mkdir(const char *name)
434 #ifdef __PCTOOL__
435 return MKDIR(name, 0777);
436 #else
437 char buffer[MAX_PATH]; /* sufficiently big */
439 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
441 /* debugf("We create the real directory '%s'\n", buffer); */
442 return MKDIR(buffer, 0777);
443 #endif
446 int sim_rmdir(const char *name)
448 #ifdef __PCTOOL__
449 return RMDIR(name);
450 #else
451 char buffer[MAX_PATH]; /* sufficiently big */
452 if(name[0] == '/')
454 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
456 /* debugf("We remove the real directory '%s'\n", buffer); */
457 return RMDIR(buffer);
459 return RMDIR(name);
460 #endif
463 int sim_remove(const char *name)
465 #ifdef __PCTOOL__
466 return REMOVE(name);
467 #else
468 char buffer[MAX_PATH]; /* sufficiently big */
470 #ifdef HAVE_DIRCACHE
471 dircache_remove(name);
472 #endif
474 if(name[0] == '/') {
475 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
477 /* debugf("We remove the real file '%s'\n", buffer); */
478 return REMOVE(buffer);
480 return REMOVE(name);
481 #endif
484 int sim_rename(const char *oldpath, const char* newpath)
486 #ifdef __PCTOOL__
487 return RENAME(oldpath, newpath);
488 #else
489 char buffer1[MAX_PATH];
490 char buffer2[MAX_PATH];
492 #ifdef HAVE_DIRCACHE
493 dircache_rename(oldpath, newpath);
494 #endif
496 if(oldpath[0] == '/') {
497 snprintf(buffer1, sizeof(buffer1), "%s%s", get_sim_rootdir(),
498 oldpath);
499 snprintf(buffer2, sizeof(buffer2), "%s%s", get_sim_rootdir(),
500 newpath);
502 /* debugf("We rename the real file '%s' to '%s'\n", buffer1, buffer2); */
503 return RENAME(buffer1, buffer2);
505 return -1;
506 #endif
509 /* rockbox off_t may be different from system off_t */
510 long sim_lseek(int fildes, long offset, int whence)
512 return lseek(fildes, offset, whence);
515 long sim_filesize(int fd)
517 #ifdef WIN32
518 return _filelength(fd);
519 #else
520 struct stat buf;
522 if (!fstat(fd, &buf))
523 return buf.st_size;
524 else
525 return -1;
526 #endif
529 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
531 #ifdef HAVE_MULTIVOLUME
532 if (volume != 0) {
533 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
535 if (size) *size = 0;
536 if (free) *free = 0;
537 return;
539 #endif
541 #ifdef WIN32
542 long secperclus, bytespersec, free_clusters, num_clusters;
544 if (GetDiskFreeSpace(NULL, &secperclus, &bytespersec, &free_clusters,
545 &num_clusters)) {
546 if (size)
547 *size = num_clusters * secperclus / 2 * (bytespersec / 512);
548 if (free)
549 *free = free_clusters * secperclus / 2 * (bytespersec / 512);
551 #else
552 struct statfs fs;
554 if (!statfs(".", &fs)) {
555 DEBUGF("statfs: bsize=%d blocks=%ld free=%ld\n",
556 (int)fs.f_bsize, fs.f_blocks, fs.f_bfree);
557 if (size)
558 *size = fs.f_blocks * (fs.f_bsize / 1024);
559 if (free)
560 *free = fs.f_bfree * (fs.f_bsize / 1024);
562 #endif
563 else {
564 if (size)
565 *size = 0;
566 if (free)
567 *free = 0;
571 int sim_fsync(int fd)
573 #ifdef WIN32
574 return _commit(fd);
575 #else
576 return fsync(fd);
577 #endif
580 #ifdef WIN32
581 /* sim-win32 */
582 #define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
583 #define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
584 #define dlclose(_x_) FreeLibrary(_x_)
585 #else
586 /* sim-x11 */
587 #include <dlfcn.h>
588 #endif
590 #define TEMP_CODEC_FILE SIMULATOR_DEFAULT_ROOT "/_temp_codec%d.dll"
592 void *sim_codec_load_ram(char* codecptr, int size, void **pd)
594 void *hdr;
595 char path[MAX_PATH];
596 int fd;
597 int codec_count;
598 #ifdef WIN32
599 char buf[MAX_PATH];
600 #endif
602 *pd = NULL;
604 /* We have to create the dynamic link library file from ram so we
605 can simulate the codec loading. With voice and crossfade,
606 multiple codecs may be loaded at the same time, so we need
607 to find an unused filename */
608 for (codec_count = 0; codec_count < 10; codec_count++)
610 snprintf(path, sizeof(path), TEMP_CODEC_FILE, codec_count);
612 fd = OPEN(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRWXU);
613 if (fd >= 0)
614 break; /* Created a file ok */
616 if (fd < 0)
618 DEBUGF("failed to open for write: %s\n", path);
619 return NULL;
622 if (write(fd, codecptr, size) != size) {
623 DEBUGF("write failed");
624 return NULL;
626 close(fd);
628 /* Now load the library. */
629 *pd = dlopen(path, RTLD_NOW);
630 if (*pd == NULL) {
631 DEBUGF("failed to load %s\n", path);
632 #ifdef WIN32
633 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
634 buf, sizeof buf, NULL);
635 DEBUGF("dlopen(%s): %s\n", path, buf);
636 #else
637 DEBUGF("dlopen(%s): %s\n", path, dlerror());
638 #endif
639 return NULL;
642 hdr = dlsym(*pd, "__header");
643 if (!hdr)
644 hdr = dlsym(*pd, "___header");
646 return hdr; /* maybe NULL if symbol not present */
649 void sim_codec_close(void *pd)
651 dlclose(pd);
654 void *sim_plugin_load(char *plugin, void **pd)
656 void *hdr;
657 char path[MAX_PATH];
658 #ifdef WIN32
659 char buf[MAX_PATH];
660 #endif
662 snprintf(path, sizeof(path), SIMULATOR_DEFAULT_ROOT "%s", plugin);
664 *pd = NULL;
666 *pd = dlopen(path, RTLD_NOW);
667 if (*pd == NULL) {
668 DEBUGF("failed to load %s\n", plugin);
669 #ifdef WIN32
670 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
671 buf, sizeof(buf), NULL);
672 DEBUGF("dlopen(%s): %s\n", path, buf);
673 #else
674 DEBUGF("dlopen(%s): %s\n", path, dlerror());
675 #endif
676 return NULL;
679 hdr = dlsym(*pd, "__header");
680 if (!hdr)
681 hdr = dlsym(*pd, "___header");
683 return hdr; /* maybe NULL if symbol not present */
686 void sim_plugin_close(void *pd)
688 dlclose(pd);
691 #ifdef WIN32
692 static unsigned old_cp;
694 void debug_exit(void)
696 /* Reset console output codepage */
697 SetConsoleOutputCP(old_cp);
700 void debug_init(void)
702 old_cp = GetConsoleOutputCP();
703 /* Set console output codepage to UTF8. Only works
704 * correctly when the console uses a truetype font. */
705 SetConsoleOutputCP(65001);
706 atexit(debug_exit);
708 #else
709 void debug_init(void)
711 /* nothing to be done */
713 #endif
715 void debugf(const char *fmt, ...)
717 va_list ap;
718 va_start( ap, fmt );
719 vfprintf( stderr, fmt, ap );
720 va_end( ap );
723 void ldebugf(const char* file, int line, const char *fmt, ...)
725 va_list ap;
726 va_start( ap, fmt );
727 fprintf( stderr, "%s:%d ", file, line );
728 vfprintf( stderr, fmt, ap );
729 va_end( ap );
732 /* rockbox off_t may be different from system off_t */
733 int sim_ftruncate(int fd, long length)
735 #ifdef WIN32
736 return _chsize(fd, length);
737 #else
738 return ftruncate(fd, length);
739 #endif