Mark some local variables with 'static'.
[kugel-rb.git] / uisimulator / common / io.c
blob4c0fa33be5ff11b7ea18ed52951d7bf6412eab7a
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 #include "config.h"
30 #define HAVE_STATVFS (0 == (CONFIG_PLATFORM & PLATFORM_ANDROID) && !defined(WIN32))
32 #if HAVE_STATVFS
33 #include <sys/statvfs.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 #include <fcntl.h>
48 #if (CONFIG_PLATFORM & PLATFORM_SDL)
49 #include <SDL.h>
50 #include <SDL_thread.h>
51 #include "thread-sdl.h"
52 #else
53 #define sim_thread_unlock() NULL
54 #define sim_thread_lock(a)
55 #endif
56 #include "thread.h"
57 #include "kernel.h"
58 #include "debug.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;
257 /* shut up gcc */
258 default:
259 result = -1;
262 /* Regain our status as current */
263 if (mythread != NULL)
265 sim_thread_lock(mythread);
268 return result;
271 #if !defined(__PCTOOL__) && !defined(APPLICATION)
272 static const char *get_sim_pathname(const char *name)
274 static char buffer[MAX_PATH]; /* sufficiently big */
276 if(name[0] == '/')
278 snprintf(buffer, sizeof(buffer), "%s%s",
279 sim_root_dir != NULL ? sim_root_dir : SIMULATOR_DEFAULT_ROOT, name);
280 return buffer;
282 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n", name);
283 return name;
285 #else
286 #define get_sim_pathname(name) name
287 #endif
289 MYDIR *sim_opendir(const char *name)
291 DIR_T *dir;
293 dir = (DIR_T *) OPENDIR(get_sim_pathname(name));
295 if (dir)
297 MYDIR *my = (MYDIR *)malloc(sizeof(MYDIR));
298 my->dir = dir;
299 my->name = (char *)malloc(strlen(name)+1);
300 strcpy(my->name, name);
302 return my;
304 /* failed open, return NULL */
305 return (MYDIR *)0;
308 struct sim_dirent *sim_readdir(MYDIR *dir)
310 char buffer[MAX_PATH]; /* sufficiently big */
311 static struct sim_dirent secret;
312 STAT_T s;
313 DIRENT_T *x11 = READDIR(dir->dir);
314 struct tm* tm;
316 if(!x11)
317 return (struct sim_dirent *)0;
319 strcpy((char *)secret.d_name, OS_TO_UTF8(x11->d_name));
321 /* build file name */
322 snprintf(buffer, sizeof(buffer), "%s/%s",
323 get_sim_pathname(dir->name), secret.d_name);
324 STAT(buffer, &s); /* get info */
326 #define ATTR_DIRECTORY 0x10
328 secret.attribute = S_ISDIR(s.st_mode)?ATTR_DIRECTORY:0;
329 secret.size = s.st_size;
331 tm = localtime(&(s.st_mtime));
332 secret.wrtdate = ((tm->tm_year - 80) << 9) |
333 ((tm->tm_mon + 1) << 5) |
334 tm->tm_mday;
335 secret.wrttime = (tm->tm_hour << 11) |
336 (tm->tm_min << 5) |
337 (tm->tm_sec >> 1);
338 return &secret;
341 void sim_closedir(MYDIR *dir)
343 free(dir->name);
344 CLOSEDIR(dir->dir);
346 free(dir);
349 int sim_open(const char *name, int o, ...)
351 int opts = rockbox2sim(o);
352 int ret;
353 if (num_openfiles >= MAX_OPEN_FILES)
354 return -2;
356 if (opts & O_CREAT)
358 va_list ap;
359 va_start(ap, o);
360 mode_t mode = va_arg(ap, unsigned int);
361 ret = OPEN(get_sim_pathname(name), opts, mode);
362 va_end(ap);
364 else
365 ret = OPEN(get_sim_pathname(name), opts);
367 if (ret >= 0)
368 num_openfiles++;
369 return ret;
372 int sim_close(int fd)
374 int ret;
375 ret = CLOSE(fd);
376 if (ret == 0)
377 num_openfiles--;
378 return ret;
381 int sim_creat(const char *name, mode_t mode)
383 return OPEN(get_sim_pathname(name), O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, mode);
386 ssize_t sim_read(int fd, void *buf, size_t count)
388 ssize_t result;
390 mutex_lock(&io.sim_mutex);
392 /* Setup parameters */
393 io.fd = fd;
394 io.buf = buf;
395 io.count = count;
397 result = io_trigger_and_wait(IO_READ);
399 mutex_unlock(&io.sim_mutex);
401 return result;
404 ssize_t sim_write(int fd, const void *buf, size_t count)
406 ssize_t result;
408 mutex_lock(&io.sim_mutex);
410 io.fd = fd;
411 io.buf = (void*)buf;
412 io.count = count;
414 result = io_trigger_and_wait(IO_WRITE);
416 mutex_unlock(&io.sim_mutex);
418 return result;
421 int sim_mkdir(const char *name)
423 return MKDIR(get_sim_pathname(name), 0777);
426 int sim_rmdir(const char *name)
428 return RMDIR(get_sim_pathname(name));
431 int sim_remove(const char *name)
433 #ifdef HAVE_DIRCACHE
434 dircache_remove(name);
435 #endif
436 return REMOVE(get_sim_pathname(name));
439 int sim_rename(const char *oldname, const char *newname)
441 char sim_old[MAX_PATH];
442 char sim_new[MAX_PATH];
443 #ifdef HAVE_DIRCACHE
444 dircache_rename(oldname, newname);
445 #endif
446 // This is needed as get_sim_pathname() has a static buffer
447 strncpy(sim_old, get_sim_pathname(oldname), MAX_PATH);
448 strncpy(sim_new, get_sim_pathname(newname), MAX_PATH);
449 return RENAME(sim_old, sim_new);
452 /* rockbox off_t may be different from system off_t */
453 long sim_lseek(int fildes, long offset, int whence)
455 return lseek(fildes, offset, whence);
458 long sim_filesize(int fd)
460 #ifdef WIN32
461 return _filelength(fd);
462 #else
463 struct stat buf;
465 if (!fstat(fd, &buf))
466 return buf.st_size;
467 else
468 return -1;
469 #endif
472 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
474 #ifdef HAVE_MULTIVOLUME
475 if (volume != 0) {
476 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
478 if (size) *size = 0;
479 if (free) *free = 0;
480 return;
482 #endif
484 #ifdef WIN32
485 long secperclus, bytespersec, free_clusters, num_clusters;
487 if (GetDiskFreeSpace(NULL, &secperclus, &bytespersec, &free_clusters,
488 &num_clusters)) {
489 if (size)
490 *size = num_clusters * secperclus / 2 * (bytespersec / 512);
491 if (free)
492 *free = free_clusters * secperclus / 2 * (bytespersec / 512);
494 #elif HAVE_STATVFS
495 struct statvfs vfs;
497 if (!statvfs(".", &vfs)) {
498 DEBUGF("statvfs: frsize=%d blocks=%ld free=%ld\n",
499 (int)vfs.f_frsize, (long)vfs.f_blocks, (long)vfs.f_bfree);
500 if (size)
501 *size = vfs.f_blocks / 2 * (vfs.f_frsize / 512);
502 if (free)
503 *free = vfs.f_bfree / 2 * (vfs.f_frsize / 512);
504 } else
505 #endif
507 if (size)
508 *size = 0;
509 if (free)
510 *free = 0;
514 int sim_fsync(int fd)
516 #ifdef WIN32
517 return _commit(fd);
518 #else
519 return fsync(fd);
520 #endif
523 #ifdef WIN32
524 /* sim-win32 */
525 #define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
526 #define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
527 #define dlclose(_x_) FreeLibrary(_x_)
528 #else
529 /* sim-x11 */
530 #include <dlfcn.h>
531 #endif
533 void *sim_codec_load_ram(char* codecptr, int size, void **pd)
535 void *hdr;
536 char path[MAX_PATH];
537 int fd;
538 int codec_count;
539 #ifdef WIN32
540 char buf[MAX_PATH];
541 #endif
543 *pd = NULL;
545 /* We have to create the dynamic link library file from ram so we
546 can simulate the codec loading. With voice and crossfade,
547 multiple codecs may be loaded at the same time, so we need
548 to find an unused filename */
549 for (codec_count = 0; codec_count < 10; codec_count++)
551 #if (CONFIG_PLATFORM & PLATFORM_ANDROID)
552 /* we need that path fixed, since get_user_file_path()
553 * gives us the folder on the sdcard where we cannot load libraries
554 * from (no exec permissions)
556 snprintf(path, sizeof(path),
557 "/data/data/org.rockbox/app_rockbox/libtemp_codec_%d.so",
558 codec_count);
559 #else
560 char name[MAX_PATH];
561 const char *_name = get_user_file_path(ROCKBOX_DIR, 0, name, sizeof(name));
562 snprintf(path, sizeof(path), "%s/_temp_codec%d.dll", get_sim_pathname(_name), codec_count);
563 #endif
564 fd = OPEN(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRWXU);
565 if (fd >= 0)
566 break; /* Created a file ok */
568 if (fd < 0)
570 DEBUGF("failed to open for write: %s\n", path);
571 return NULL;
574 if (write(fd, codecptr, size) != size)
576 DEBUGF("write failed");
577 return NULL;
579 close(fd);
581 /* Now load the library. */
582 *pd = dlopen(path, RTLD_NOW);
583 if (*pd == NULL)
585 DEBUGF("failed to load %s\n", path);
586 #ifdef WIN32
587 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
588 buf, sizeof buf, NULL);
589 DEBUGF("dlopen(%s): %s\n", path, buf);
590 #else
591 DEBUGF("dlopen(%s): %s\n", path, dlerror());
592 #endif
593 return NULL;
596 hdr = dlsym(*pd, "__header");
597 if (!hdr)
598 hdr = dlsym(*pd, "___header");
600 return hdr; /* maybe NULL if symbol not present */
603 void sim_codec_close(void *pd)
605 dlclose(pd);
608 void *sim_plugin_load(char *plugin, void **pd)
610 void *hdr;
611 char path[MAX_PATH];
612 #ifdef WIN32
613 char buf[MAX_PATH];
614 #endif
616 snprintf(path, sizeof(path), "%s", get_sim_pathname(plugin));
618 *pd = NULL;
620 *pd = dlopen(path, RTLD_NOW);
621 if (*pd == NULL) {
622 DEBUGF("failed to load %s\n", plugin);
623 #ifdef WIN32
624 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
625 buf, sizeof(buf), NULL);
626 DEBUGF("dlopen(%s): %s\n", path, buf);
627 #else
628 DEBUGF("dlopen(%s): %s\n", path, dlerror());
629 #endif
630 return NULL;
633 hdr = dlsym(*pd, "__header");
634 if (!hdr)
635 hdr = dlsym(*pd, "___header");
637 return hdr; /* maybe NULL if symbol not present */
640 void sim_plugin_close(void *pd)
642 dlclose(pd);
645 #ifdef WIN32
646 static unsigned old_cp;
648 void debug_exit(void)
650 /* Reset console output codepage */
651 SetConsoleOutputCP(old_cp);
654 void debug_init(void)
656 old_cp = GetConsoleOutputCP();
657 /* Set console output codepage to UTF8. Only works
658 * correctly when the console uses a truetype font. */
659 SetConsoleOutputCP(65001);
660 atexit(debug_exit);
662 #else
663 void debug_init(void)
665 /* nothing to be done */
667 #endif
669 void debugf(const char *fmt, ...)
671 va_list ap;
672 va_start( ap, fmt );
673 vfprintf( stderr, fmt, ap );
674 va_end( ap );
677 void ldebugf(const char* file, int line, const char *fmt, ...)
679 va_list ap;
680 va_start( ap, fmt );
681 fprintf( stderr, "%s:%d ", file, line );
682 vfprintf( stderr, fmt, ap );
683 va_end( ap );
686 /* rockbox off_t may be different from system off_t */
687 int sim_ftruncate(int fd, long length)
689 #ifdef WIN32
690 return _chsize(fd, length);
691 #else
692 return ftruncate(fd, length);
693 #endif