Simplify initing of the screens[] struct by using an initializer, also some reorderin...
[kugel-rb.git] / uisimulator / common / io.c
blob73eda239ffe6c6b8a78b689b0b0688b28ab06503
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>
50 #include <SDL.h>
51 #include <SDL_thread.h>
52 #include "thread.h"
53 #include "kernel.h"
54 #include "debug.h"
55 #include "config.h"
56 #include "ata.h" /* for IF_MV2 et al. */
58 /* Windows (and potentially other OSes) distinguish binary and text files.
59 * Define a dummy for the others. */
60 #ifndef O_BINARY
61 #define O_BINARY 0
62 #endif
64 /* Unicode compatibility for win32 */
65 #if defined __MINGW32__
66 /* Rockbox unicode functions */
67 extern const unsigned char* utf8decode(const unsigned char *utf8,
68 unsigned short *ucs);
69 extern unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8);
71 /* Static buffers for the conversion results. This isn't thread safe,
72 * but it's sufficient for rockbox. */
73 static unsigned char convbuf1[3*MAX_PATH];
74 static unsigned char convbuf2[3*MAX_PATH];
76 static wchar_t* utf8_to_ucs2(const unsigned char *utf8, void *buffer)
78 wchar_t *ucs = buffer;
80 while (*utf8)
81 utf8 = utf8decode(utf8, ucs++);
83 *ucs = 0;
84 return buffer;
86 static unsigned char *ucs2_to_utf8(const wchar_t *ucs, unsigned char *buffer)
88 unsigned char *utf8 = buffer;
90 while (*ucs)
91 utf8 = utf8encode(*ucs++, utf8);
93 *utf8 = 0;
94 return buffer;
97 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
98 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
99 #define DIR_T _WDIR
100 #define DIRENT_T struct _wdirent
101 #define STAT_T struct _stat
102 extern int _wmkdir(const wchar_t*);
103 extern int _wrmdir(const wchar_t*);
104 #define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
105 #define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
106 #define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
107 #define READDIR(a) (_wreaddir)(a)
108 #define CLOSEDIR(a) (_wclosedir)(a)
109 #define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
110 #define OPEN(a,b,c) (_wopen)(UTF8_TO_OS(a),b,c)
111 #define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
112 #define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
114 #else /* !__MINGW32__ */
116 #define UTF8_TO_OS(a) (a)
117 #define OS_TO_UTF8(a) (a)
118 #define DIR_T DIR
119 #define DIRENT_T struct dirent
120 #define STAT_T struct stat
121 #define MKDIR(a,b) (mkdir)(a,b)
122 #define RMDIR(a) (rmdir)(a)
123 #define OPENDIR(a) (opendir)(a)
124 #define READDIR(a) (readdir)(a)
125 #define CLOSEDIR(a) (closedir)(a)
126 #define STAT(a,b) (stat)(a,b)
127 #define OPEN(a,b,c) (open)(a,b,c)
128 #define REMOVE(a) (remove)(a)
129 #define RENAME(a,b) (rename)(a,b)
131 #endif /* !__MINGW32__ */
134 #ifdef HAVE_DIRCACHE
135 void dircache_remove(const char *name);
136 void dircache_rename(const char *oldpath, const char *newpath);
137 #endif
139 #define SIMULATOR_ARCHOS_ROOT "archos"
141 struct sim_dirent {
142 unsigned char d_name[MAX_PATH];
143 int attribute;
144 long size;
145 long startcluster;
146 unsigned short wrtdate; /* Last write date */
147 unsigned short wrttime; /* Last write time */
150 struct dirstruct {
151 void *dir; /* actually a DIR* dir */
152 char *name;
153 } SIM_DIR;
155 struct mydir {
156 DIR_T *dir;
157 char *name;
160 typedef struct mydir MYDIR;
162 #if 1 /* maybe this needs disabling for MSVC... */
163 static unsigned int rockbox2sim(int opt)
165 int newopt = O_BINARY;
167 if(opt & 1)
168 newopt |= O_WRONLY;
169 if(opt & 2)
170 newopt |= O_RDWR;
171 if(opt & 4)
172 newopt |= O_CREAT;
173 if(opt & 8)
174 newopt |= O_APPEND;
175 if(opt & 0x10)
176 newopt |= O_TRUNC;
178 return newopt;
180 #endif
182 /** Simulator I/O engine routines **/
183 enum
185 IO_QUIT = -1,
186 IO_OPEN,
187 IO_CLOSE,
188 IO_READ,
189 IO_WRITE,
192 struct sim_io
194 SDL_mutex *m; /* Mutex for condition */
195 SDL_cond *c; /* Condition for synchronizing threads */
196 SDL_Thread *t; /* The I/O thread */
197 struct mutex sim_mutex; /* Rockbox mutex */
198 volatile int cmd; /* The command to perform */
199 volatile int ready; /* I/O ready flag - 1= ready */
200 volatile int fd; /* The file to read/write */
201 void* volatile buf; /* The buffer to read/write */
202 volatile size_t count; /* Number of bytes to read/write */
203 ssize_t result; /* Result of operation */
206 static struct sim_io io;
208 static int io_thread(void *data)
210 SDL_LockMutex(io.m);
212 io.ready = 1; /* Indication mutex has been locked */
214 for (;;)
216 SDL_CondWait(io.c, io.m); /* unlock mutex and wait */
218 switch (io.cmd)
220 case IO_READ:
221 io.result = read(io.fd, io.buf, io.count);
222 io.ready = 1;
223 break;
224 case IO_WRITE:
225 io.result = write(io.fd, io.buf, io.count);
226 io.ready = 1;
227 break;
228 case IO_QUIT:
229 SDL_UnlockMutex(io.m);
230 return 0;
234 (void)data;
237 bool sim_io_init(void)
239 io.ready = 0;
241 io.m = SDL_CreateMutex();
242 if (io.m == NULL)
244 fprintf(stderr, "Failed to create IO mutex\n");
245 return false;
248 io.c = SDL_CreateCond();
249 if (io.c == NULL)
251 fprintf(stderr, "Failed to create IO cond\n");
252 return false;
255 io.t = SDL_CreateThread(io_thread, NULL);
256 if (io.t == NULL)
258 fprintf(stderr, "Failed to create IO thread\n");
259 return false;
262 /* Wait for IO thread to lock mutex */
263 while (!io.ready)
264 SDL_Delay(0);
266 /* Wait for it to unlock */
267 SDL_LockMutex(io.m);
268 /* Free it for another thread */
269 SDL_UnlockMutex(io.m);
271 return true;
274 int ata_init(void)
276 /* Initialize the rockbox kernel objects on a rockbox thread */
277 mutex_init(&io.sim_mutex);
278 return 1;
281 void sim_io_shutdown(void)
283 SDL_LockMutex(io.m);
285 io.cmd = IO_QUIT;
287 SDL_CondSignal(io.c);
288 SDL_UnlockMutex(io.m);
290 SDL_WaitThread(io.t, NULL);
292 SDL_DestroyMutex(io.m);
293 SDL_DestroyCond(io.c);
296 static void io_trigger_and_wait(int cmd)
298 /* Lock mutex before setting up new params and signaling condition */
299 SDL_LockMutex(io.m);
301 io.cmd = cmd;
302 io.ready = 0;
304 /* Get thread started */
305 SDL_CondSignal(io.c);
307 /* Let it run */
308 SDL_UnlockMutex(io.m);
310 /* Wait for IO to complete */
311 while (!io.ready)
312 yield();
315 MYDIR *sim_opendir(const char *name)
317 char buffer[MAX_PATH]; /* sufficiently big */
318 DIR_T *dir;
320 #ifndef __PCTOOL__
321 if(name[0] == '/')
323 snprintf(buffer, sizeof(buffer), "%s%s", SIMULATOR_ARCHOS_ROOT, name);
324 dir=(DIR_T *)OPENDIR(buffer);
326 else
327 #endif
328 dir=(DIR_T *)OPENDIR(name);
330 if(dir) {
331 MYDIR *my = (MYDIR *)malloc(sizeof(MYDIR));
332 my->dir = dir;
333 my->name = (char *)strdup(name);
335 return my;
337 /* failed open, return NULL */
338 return (MYDIR *)0;
341 struct sim_dirent *sim_readdir(MYDIR *dir)
343 char buffer[512]; /* sufficiently big */
344 static struct sim_dirent secret;
345 STAT_T s;
346 DIRENT_T *x11 = READDIR(dir->dir);
347 struct tm* tm;
349 if(!x11)
350 return (struct sim_dirent *)0;
352 strcpy((char *)secret.d_name, OS_TO_UTF8(x11->d_name));
354 /* build file name */
355 #ifdef __PCTOOL__
356 snprintf(buffer, sizeof(buffer), "%s/%s", dir->name, secret.d_name);
357 #else
358 snprintf(buffer, sizeof(buffer), SIMULATOR_ARCHOS_ROOT "%s/%s",
359 dir->name, secret.d_name);
360 #endif
361 STAT(buffer, &s); /* get info */
363 #define ATTR_DIRECTORY 0x10
365 secret.attribute = S_ISDIR(s.st_mode)?ATTR_DIRECTORY:0;
366 secret.size = s.st_size;
368 tm = localtime(&(s.st_mtime));
369 secret.wrtdate = ((tm->tm_year - 80) << 9) |
370 ((tm->tm_mon + 1) << 5) |
371 tm->tm_mday;
372 secret.wrttime = (tm->tm_hour << 11) |
373 (tm->tm_min << 5) |
374 (tm->tm_sec >> 1);
375 return &secret;
378 void sim_closedir(MYDIR *dir)
380 free(dir->name);
381 CLOSEDIR(dir->dir);
383 free(dir);
386 int sim_open(const char *name, int o)
388 char buffer[MAX_PATH]; /* sufficiently big */
389 int opts = rockbox2sim(o);
391 #ifndef __PCTOOL__
392 if(name[0] == '/')
394 snprintf(buffer, sizeof(buffer), "%s%s", SIMULATOR_ARCHOS_ROOT, name);
396 debugf("We open the real file '%s'\n", buffer);
397 return OPEN(buffer, opts, 0666);
400 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n",
401 name);
402 return -1;
403 #else
404 return OPEN(name, opts, 0666);
405 #endif
409 int sim_creat(const char *name)
411 #ifndef __PCTOOL__
412 char buffer[MAX_PATH]; /* sufficiently big */
413 if(name[0] == '/')
415 snprintf(buffer, sizeof(buffer), "%s%s", SIMULATOR_ARCHOS_ROOT, name);
417 debugf("We create the real file '%s'\n", buffer);
418 return OPEN(buffer, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666);
420 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n", name);
421 return -1;
422 #else
423 return OPEN(name, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666);
424 #endif
427 ssize_t sim_read(int fd, void *buf, size_t count)
429 ssize_t result;
431 mutex_lock(&io.sim_mutex);
433 /* Setup parameters */
434 io.fd = fd;
435 io.buf = buf;
436 io.count = count;
438 io_trigger_and_wait(IO_READ);
440 result = io.result;
442 mutex_unlock(&io.sim_mutex);
444 return result;
447 ssize_t sim_write(int fd, const void *buf, size_t count)
449 ssize_t result;
451 mutex_lock(&io.sim_mutex);
453 io.fd = fd;
454 io.buf = (void*)buf;
455 io.count = count;
457 io_trigger_and_wait(IO_WRITE);
459 result = io.result;
461 mutex_unlock(&io.sim_mutex);
463 return result;
466 int sim_mkdir(const char *name)
468 #ifdef __PCTOOL__
469 return MKDIR(name, 0777);
470 #else
471 char buffer[MAX_PATH]; /* sufficiently big */
473 snprintf(buffer, sizeof(buffer), "%s%s", SIMULATOR_ARCHOS_ROOT, name);
475 debugf("We create the real directory '%s'\n", buffer);
476 return MKDIR(buffer, 0777);
477 #endif
480 int sim_rmdir(const char *name)
482 #ifdef __PCTOOL__
483 return RMDIR(name);
484 #else
485 char buffer[MAX_PATH]; /* sufficiently big */
486 if(name[0] == '/')
488 snprintf(buffer, sizeof(buffer), "%s%s", SIMULATOR_ARCHOS_ROOT, name);
490 debugf("We remove the real directory '%s'\n", buffer);
491 return RMDIR(buffer);
493 return RMDIR(name);
494 #endif
497 int sim_remove(const char *name)
499 #ifdef __PCTOOL__
500 return REMOVE(name);
501 #else
502 char buffer[MAX_PATH]; /* sufficiently big */
504 #ifdef HAVE_DIRCACHE
505 dircache_remove(name);
506 #endif
508 if(name[0] == '/') {
509 snprintf(buffer, sizeof(buffer), "%s%s", SIMULATOR_ARCHOS_ROOT, name);
511 debugf("We remove the real file '%s'\n", buffer);
512 return REMOVE(buffer);
514 return REMOVE(name);
515 #endif
518 int sim_rename(const char *oldpath, const char* newpath)
520 #ifdef __PCTOOL__
521 return RENAME(oldpath, newpath);
522 #else
523 char buffer1[MAX_PATH];
524 char buffer2[MAX_PATH];
526 #ifdef HAVE_DIRCACHE
527 dircache_rename(oldpath, newpath);
528 #endif
530 if(oldpath[0] == '/') {
531 snprintf(buffer1, sizeof(buffer1), "%s%s", SIMULATOR_ARCHOS_ROOT,
532 oldpath);
533 snprintf(buffer2, sizeof(buffer2), "%s%s", SIMULATOR_ARCHOS_ROOT,
534 newpath);
536 debugf("We rename the real file '%s' to '%s'\n", buffer1, buffer2);
537 return RENAME(buffer1, buffer2);
539 return -1;
540 #endif
543 /* rockbox off_t may be different from system off_t */
544 long sim_lseek(int fildes, long offset, int whence)
546 return lseek(fildes, offset, whence);
549 long sim_filesize(int fd)
551 #ifdef WIN32
552 return _filelength(fd);
553 #else
554 struct stat buf;
556 if (!fstat(fd, &buf))
557 return buf.st_size;
558 else
559 return -1;
560 #endif
563 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
565 #ifdef HAVE_MULTIVOLUME
566 if (volume != 0) {
567 debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",
568 volume);
570 if (size) *size = 0;
571 if (free) *free = 0;
572 return;
574 #endif
576 #ifdef WIN32
577 long secperclus, bytespersec, free_clusters, num_clusters;
579 if (GetDiskFreeSpace(NULL, &secperclus, &bytespersec, &free_clusters,
580 &num_clusters)) {
581 if (size)
582 *size = num_clusters * secperclus / 2 * (bytespersec / 512);
583 if (free)
584 *free = free_clusters * secperclus / 2 * (bytespersec / 512);
586 #else
587 struct statfs fs;
589 if (!statfs(".", &fs)) {
590 DEBUGF("statfs: bsize=%d blocks=%ld free=%ld\n",
591 (int)fs.f_bsize, fs.f_blocks, fs.f_bfree);
592 if (size)
593 *size = fs.f_blocks * (fs.f_bsize / 1024);
594 if (free)
595 *free = fs.f_bfree * (fs.f_bsize / 1024);
597 #endif
598 else {
599 if (size)
600 *size = 0;
601 if (free)
602 *free = 0;
606 int sim_fsync(int fd)
608 #ifdef WIN32
609 return _commit(fd);
610 #else
611 return fsync(fd);
612 #endif
615 #ifdef WIN32
616 /* sim-win32 */
617 #define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
618 #define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
619 #define dlclose(_x_) FreeLibrary(_x_)
620 #else
621 /* sim-x11 */
622 #include <dlfcn.h>
623 #endif
625 #define TEMP_CODEC_FILE "archos/_temp_codec%d.dll"
627 void *sim_codec_load_ram(char* codecptr, int size,
628 void* ptr2, int bufwrap, void **pd)
630 void *hdr;
631 char path[MAX_PATH];
632 int fd;
633 int copy_n;
634 int codec_count;
635 #ifdef WIN32
636 char buf[MAX_PATH];
637 #endif
639 *pd = NULL;
641 /* We have to create the dynamic link library file from ram so we
642 can simulate the codec loading. With voice and crossfade,
643 multiple codecs may be loaded at the same time, so we need
644 to find an unused filename */
645 for (codec_count = 0; codec_count < 10; codec_count++)
647 snprintf(path, sizeof(path), TEMP_CODEC_FILE, codec_count);
649 fd = OPEN(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRWXU);
650 if (fd >= 0)
651 break; /* Created a file ok */
653 if (fd < 0)
655 DEBUGF("failed to open for write: %s\n", path);
656 return NULL;
659 if (bufwrap == 0)
660 bufwrap = size;
662 copy_n = bufwrap < size ? bufwrap : size;
663 if (write(fd, codecptr, copy_n) != copy_n) {
664 DEBUGF("write failed");
665 return NULL;
667 size -= copy_n;
668 if (size > 0) {
669 if (write(fd, ptr2, size) != size) {
670 DEBUGF("write failed [2]");
671 return NULL;
674 close(fd);
676 /* Now load the library. */
677 *pd = dlopen(path, RTLD_NOW);
678 if (*pd == NULL) {
679 DEBUGF("failed to load %s\n", path);
680 #ifdef WIN32
681 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
682 buf, sizeof buf, NULL);
683 DEBUGF("dlopen(%s): %s\n", path, buf);
684 #else
685 DEBUGF("dlopen(%s): %s\n", path, dlerror());
686 #endif
687 return NULL;
690 hdr = dlsym(*pd, "__header");
691 if (!hdr)
692 hdr = dlsym(*pd, "___header");
694 return hdr; /* maybe NULL if symbol not present */
697 void sim_codec_close(void *pd)
699 dlclose(pd);
702 void *sim_plugin_load(char *plugin, void **pd)
704 void *hdr;
705 char path[MAX_PATH];
706 #ifdef WIN32
707 char buf[MAX_PATH];
708 #endif
710 snprintf(path, sizeof(path), "archos%s", plugin);
712 *pd = NULL;
714 *pd = dlopen(path, RTLD_NOW);
715 if (*pd == NULL) {
716 DEBUGF("failed to load %s\n", plugin);
717 #ifdef WIN32
718 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
719 buf, sizeof(buf), NULL);
720 DEBUGF("dlopen(%s): %s\n", path, buf);
721 #else
722 DEBUGF("dlopen(%s): %s\n", path, dlerror());
723 #endif
724 return NULL;
727 hdr = dlsym(*pd, "__header");
728 if (!hdr)
729 hdr = dlsym(*pd, "___header");
731 return hdr; /* maybe NULL if symbol not present */
734 void sim_plugin_close(void *pd)
736 dlclose(pd);
739 #ifdef WIN32
740 static unsigned old_cp;
742 void debug_exit(void)
744 /* Reset console output codepage */
745 SetConsoleOutputCP(old_cp);
748 void debug_init(void)
750 old_cp = GetConsoleOutputCP();
751 /* Set console output codepage to UTF8. Only works
752 * correctly when the console uses a truetype font. */
753 SetConsoleOutputCP(65001);
754 atexit(debug_exit);
756 #else
757 void debug_init(void)
759 /* nothing to be done */
761 #endif
763 void debugf(const char *fmt, ...)
765 va_list ap;
766 va_start( ap, fmt );
767 vfprintf( stderr, fmt, ap );
768 va_end( ap );
771 void ldebugf(const char* file, int line, const char *fmt, ...)
773 va_list ap;
774 va_start( ap, fmt );
775 fprintf( stderr, "%s:%d ", file, line );
776 vfprintf( stderr, fmt, ap );
777 va_end( ap );
780 /* rockbox off_t may be different from system off_t */
781 int sim_ftruncate(int fd, long length)
783 #ifdef WIN32
784 return _chsize(fd, length);
785 #else
786 return ftruncate(fd, length);
787 #endif