connect progress signal directly to the logger.
[Rockbox.git] / uisimulator / common / io.c
blob5bd08554cb4745232bd767dc299bb720cc461cd7
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
48 #define MAX_OPEN_FILES 11
50 #include <fcntl.h>
51 #include <SDL.h>
52 #include <SDL_thread.h>
53 #include "thread.h"
54 #include "kernel.h"
55 #include "debug.h"
56 #include "config.h"
57 #include "ata.h" /* for IF_MV2 et al. */
58 #include "thread-sdl.h"
61 /* Windows (and potentially other OSes) distinguish binary and text files.
62 * Define a dummy for the others. */
63 #ifndef O_BINARY
64 #define O_BINARY 0
65 #endif
67 /* Unicode compatibility for win32 */
68 #if defined __MINGW32__
69 /* Rockbox unicode functions */
70 extern const unsigned char* utf8decode(const unsigned char *utf8,
71 unsigned short *ucs);
72 extern unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8);
74 /* Static buffers for the conversion results. This isn't thread safe,
75 * but it's sufficient for rockbox. */
76 static unsigned char convbuf1[3*MAX_PATH];
77 static unsigned char convbuf2[3*MAX_PATH];
79 static wchar_t* utf8_to_ucs2(const unsigned char *utf8, void *buffer)
81 wchar_t *ucs = buffer;
83 while (*utf8)
84 utf8 = utf8decode(utf8, ucs++);
86 *ucs = 0;
87 return buffer;
89 static unsigned char *ucs2_to_utf8(const wchar_t *ucs, unsigned char *buffer)
91 unsigned char *utf8 = buffer;
93 while (*ucs)
94 utf8 = utf8encode(*ucs++, utf8);
96 *utf8 = 0;
97 return buffer;
100 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
101 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
102 #define DIR_T _WDIR
103 #define DIRENT_T struct _wdirent
104 #define STAT_T struct _stat
105 extern int _wmkdir(const wchar_t*);
106 extern int _wrmdir(const wchar_t*);
107 #define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
108 #define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
109 #define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
110 #define READDIR(a) (_wreaddir)(a)
111 #define CLOSEDIR(a) (_wclosedir)(a)
112 #define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
113 #define OPEN(a,b,c) (_wopen)(UTF8_TO_OS(a),b,c)
114 #define CLOSE(a) (close)(a)
115 #define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
116 #define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
118 #else /* !__MINGW32__ */
120 #define UTF8_TO_OS(a) (a)
121 #define OS_TO_UTF8(a) (a)
122 #define DIR_T DIR
123 #define DIRENT_T struct dirent
124 #define STAT_T struct stat
125 #define MKDIR(a,b) (mkdir)(a,b)
126 #define RMDIR(a) (rmdir)(a)
127 #define OPENDIR(a) (opendir)(a)
128 #define READDIR(a) (readdir)(a)
129 #define CLOSEDIR(a) (closedir)(a)
130 #define STAT(a,b) (stat)(a,b)
131 #define OPEN(a,b,c) (open)(a,b,c)
132 #define CLOSE(x) (close)(x)
133 #define REMOVE(a) (remove)(a)
134 #define RENAME(a,b) (rename)(a,b)
136 #endif /* !__MINGW32__ */
139 #ifdef HAVE_DIRCACHE
140 void dircache_remove(const char *name);
141 void dircache_rename(const char *oldpath, const char *newpath);
142 #endif
145 #define SIMULATOR_DEFAULT_ROOT "archos"
146 extern const char *sim_root_dir;
148 static int num_openfiles = 0;
150 struct sim_dirent {
151 unsigned char d_name[MAX_PATH];
152 int attribute;
153 long size;
154 long startcluster;
155 unsigned short wrtdate; /* Last write date */
156 unsigned short wrttime; /* Last write time */
159 struct dirstruct {
160 void *dir; /* actually a DIR* dir */
161 char *name;
162 } SIM_DIR;
164 struct mydir {
165 DIR_T *dir;
166 char *name;
169 typedef struct mydir MYDIR;
171 #if 1 /* maybe this needs disabling for MSVC... */
172 static unsigned int rockbox2sim(int opt)
174 int newopt = O_BINARY;
176 if(opt & 1)
177 newopt |= O_WRONLY;
178 if(opt & 2)
179 newopt |= O_RDWR;
180 if(opt & 4)
181 newopt |= O_CREAT;
182 if(opt & 8)
183 newopt |= O_APPEND;
184 if(opt & 0x10)
185 newopt |= O_TRUNC;
187 return newopt;
189 #endif
191 /** Simulator I/O engine routines **/
192 #define IO_YIELD_THRESHOLD 512
194 enum
196 IO_READ,
197 IO_WRITE,
200 struct sim_io
202 struct mutex sim_mutex; /* Rockbox mutex */
203 int cmd; /* The command to perform */
204 int ready; /* I/O ready flag - 1= ready */
205 int fd; /* The file to read/write */
206 void *buf; /* The buffer to read/write */
207 size_t count; /* Number of bytes to read/write */
208 size_t accum; /* Acculated bytes transferred */
211 static struct sim_io io;
213 int ata_init(void)
215 /* Initialize the rockbox kernel objects on a rockbox thread */
216 mutex_init(&io.sim_mutex);
217 io.accum = 0;
218 return 1;
221 static ssize_t io_trigger_and_wait(int cmd)
223 void *mythread = NULL;
224 ssize_t result;
226 if (io.count > IO_YIELD_THRESHOLD ||
227 (io.accum += io.count) >= IO_YIELD_THRESHOLD)
229 /* Allow other rockbox threads to run */
230 io.accum = 0;
231 mythread = thread_sdl_thread_unlock();
234 switch (cmd)
236 case IO_READ:
237 result = read(io.fd, io.buf, io.count);
238 break;
239 case IO_WRITE:
240 result = write(io.fd, io.buf, io.count);
241 break;
244 /* Regain our status as current */
245 if (mythread != NULL)
247 thread_sdl_thread_lock(mythread);
250 return result;
253 static const char *get_sim_rootdir()
255 if (sim_root_dir != NULL)
256 return sim_root_dir;
257 return SIMULATOR_DEFAULT_ROOT;
260 MYDIR *sim_opendir(const char *name)
262 char buffer[MAX_PATH]; /* sufficiently big */
263 DIR_T *dir;
265 #ifndef __PCTOOL__
266 if(name[0] == '/')
268 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
269 dir=(DIR_T *)OPENDIR(buffer);
271 else
272 #endif
273 dir=(DIR_T *)OPENDIR(name);
275 if(dir) {
276 MYDIR *my = (MYDIR *)malloc(sizeof(MYDIR));
277 my->dir = dir;
278 my->name = (char *)strdup(name);
280 return my;
282 /* failed open, return NULL */
283 return (MYDIR *)0;
286 struct sim_dirent *sim_readdir(MYDIR *dir)
288 char buffer[MAX_PATH]; /* sufficiently big */
289 static struct sim_dirent secret;
290 STAT_T s;
291 DIRENT_T *x11 = READDIR(dir->dir);
292 struct tm* tm;
294 if(!x11)
295 return (struct sim_dirent *)0;
297 strcpy((char *)secret.d_name, OS_TO_UTF8(x11->d_name));
299 /* build file name */
300 #ifdef __PCTOOL__
301 snprintf(buffer, sizeof(buffer), "%s/%s", dir->name, secret.d_name);
302 #else
303 snprintf(buffer, sizeof(buffer), "%s/%s/%s",
304 get_sim_rootdir(), dir->name, secret.d_name);
305 #endif
306 STAT(buffer, &s); /* get info */
308 #define ATTR_DIRECTORY 0x10
310 secret.attribute = S_ISDIR(s.st_mode)?ATTR_DIRECTORY:0;
311 secret.size = s.st_size;
313 tm = localtime(&(s.st_mtime));
314 secret.wrtdate = ((tm->tm_year - 80) << 9) |
315 ((tm->tm_mon + 1) << 5) |
316 tm->tm_mday;
317 secret.wrttime = (tm->tm_hour << 11) |
318 (tm->tm_min << 5) |
319 (tm->tm_sec >> 1);
320 return &secret;
323 void sim_closedir(MYDIR *dir)
325 free(dir->name);
326 CLOSEDIR(dir->dir);
328 free(dir);
331 int sim_open(const char *name, int o)
333 char buffer[MAX_PATH]; /* sufficiently big */
334 int opts = rockbox2sim(o);
335 int ret;
337 if (num_openfiles >= MAX_OPEN_FILES)
338 return -2;
340 #ifndef __PCTOOL__
341 if(name[0] == '/')
343 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
345 /* debugf("We open the real file '%s'\n", buffer); */
346 if (num_openfiles < MAX_OPEN_FILES)
348 ret = OPEN(buffer, opts, 0666);
349 if (ret >= 0) num_openfiles++;
350 return ret;
354 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n",
355 name);
356 return -1;
357 #else
358 if (num_openfiles < MAX_OPEN_FILES)
360 ret = OPEN(buffer, opts, 0666);
361 if (ret >= 0) num_openfiles++;
362 return ret;
364 #endif
367 int sim_close(int fd)
369 int ret;
370 ret = CLOSE(fd);
371 if (ret == 0) num_openfiles--;
372 return ret;
375 int sim_creat(const char *name)
377 #ifndef __PCTOOL__
378 char buffer[MAX_PATH]; /* sufficiently big */
379 if(name[0] == '/')
381 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
383 /* debugf("We create the real file '%s'\n", buffer); */
384 return OPEN(buffer, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666);
386 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n", name);
387 return -1;
388 #else
389 return OPEN(name, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666);
390 #endif
393 ssize_t sim_read(int fd, void *buf, size_t count)
395 ssize_t result;
397 mutex_lock(&io.sim_mutex);
399 /* Setup parameters */
400 io.fd = fd;
401 io.buf = buf;
402 io.count = count;
404 result = io_trigger_and_wait(IO_READ);
406 mutex_unlock(&io.sim_mutex);
408 return result;
411 ssize_t sim_write(int fd, const void *buf, size_t count)
413 ssize_t result;
415 mutex_lock(&io.sim_mutex);
417 io.fd = fd;
418 io.buf = (void*)buf;
419 io.count = count;
421 result = io_trigger_and_wait(IO_WRITE);
423 mutex_unlock(&io.sim_mutex);
425 return result;
428 int sim_mkdir(const char *name)
430 #ifdef __PCTOOL__
431 return MKDIR(name, 0777);
432 #else
433 char buffer[MAX_PATH]; /* sufficiently big */
435 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
437 /* debugf("We create the real directory '%s'\n", buffer); */
438 return MKDIR(buffer, 0777);
439 #endif
442 int sim_rmdir(const char *name)
444 #ifdef __PCTOOL__
445 return RMDIR(name);
446 #else
447 char buffer[MAX_PATH]; /* sufficiently big */
448 if(name[0] == '/')
450 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
452 /* debugf("We remove the real directory '%s'\n", buffer); */
453 return RMDIR(buffer);
455 return RMDIR(name);
456 #endif
459 int sim_remove(const char *name)
461 #ifdef __PCTOOL__
462 return REMOVE(name);
463 #else
464 char buffer[MAX_PATH]; /* sufficiently big */
466 #ifdef HAVE_DIRCACHE
467 dircache_remove(name);
468 #endif
470 if(name[0] == '/') {
471 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
473 /* debugf("We remove the real file '%s'\n", buffer); */
474 return REMOVE(buffer);
476 return REMOVE(name);
477 #endif
480 int sim_rename(const char *oldpath, const char* newpath)
482 #ifdef __PCTOOL__
483 return RENAME(oldpath, newpath);
484 #else
485 char buffer1[MAX_PATH];
486 char buffer2[MAX_PATH];
488 #ifdef HAVE_DIRCACHE
489 dircache_rename(oldpath, newpath);
490 #endif
492 if(oldpath[0] == '/') {
493 snprintf(buffer1, sizeof(buffer1), "%s%s", get_sim_rootdir(),
494 oldpath);
495 snprintf(buffer2, sizeof(buffer2), "%s%s", get_sim_rootdir(),
496 newpath);
498 /* debugf("We rename the real file '%s' to '%s'\n", buffer1, buffer2); */
499 return RENAME(buffer1, buffer2);
501 return -1;
502 #endif
505 /* rockbox off_t may be different from system off_t */
506 long sim_lseek(int fildes, long offset, int whence)
508 return lseek(fildes, offset, whence);
511 long sim_filesize(int fd)
513 #ifdef WIN32
514 return _filelength(fd);
515 #else
516 struct stat buf;
518 if (!fstat(fd, &buf))
519 return buf.st_size;
520 else
521 return -1;
522 #endif
525 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
527 #ifdef HAVE_MULTIVOLUME
528 if (volume != 0) {
529 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
531 if (size) *size = 0;
532 if (free) *free = 0;
533 return;
535 #endif
537 #ifdef WIN32
538 long secperclus, bytespersec, free_clusters, num_clusters;
540 if (GetDiskFreeSpace(NULL, &secperclus, &bytespersec, &free_clusters,
541 &num_clusters)) {
542 if (size)
543 *size = num_clusters * secperclus / 2 * (bytespersec / 512);
544 if (free)
545 *free = free_clusters * secperclus / 2 * (bytespersec / 512);
547 #else
548 struct statfs fs;
550 if (!statfs(".", &fs)) {
551 DEBUGF("statfs: bsize=%d blocks=%ld free=%ld\n",
552 (int)fs.f_bsize, fs.f_blocks, fs.f_bfree);
553 if (size)
554 *size = fs.f_blocks * (fs.f_bsize / 1024);
555 if (free)
556 *free = fs.f_bfree * (fs.f_bsize / 1024);
558 #endif
559 else {
560 if (size)
561 *size = 0;
562 if (free)
563 *free = 0;
567 int sim_fsync(int fd)
569 #ifdef WIN32
570 return _commit(fd);
571 #else
572 return fsync(fd);
573 #endif
576 #ifdef WIN32
577 /* sim-win32 */
578 #define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
579 #define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
580 #define dlclose(_x_) FreeLibrary(_x_)
581 #else
582 /* sim-x11 */
583 #include <dlfcn.h>
584 #endif
586 #define TEMP_CODEC_FILE "archos/_temp_codec%d.dll"
588 void *sim_codec_load_ram(char* codecptr, int size, void **pd)
590 void *hdr;
591 char path[MAX_PATH];
592 int fd;
593 int codec_count;
594 #ifdef WIN32
595 char buf[MAX_PATH];
596 #endif
598 *pd = NULL;
600 /* We have to create the dynamic link library file from ram so we
601 can simulate the codec loading. With voice and crossfade,
602 multiple codecs may be loaded at the same time, so we need
603 to find an unused filename */
604 for (codec_count = 0; codec_count < 10; codec_count++)
606 snprintf(path, sizeof(path), TEMP_CODEC_FILE, codec_count);
608 fd = OPEN(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRWXU);
609 if (fd >= 0)
610 break; /* Created a file ok */
612 if (fd < 0)
614 DEBUGF("failed to open for write: %s\n", path);
615 return NULL;
618 if (write(fd, codecptr, size) != size) {
619 DEBUGF("write failed");
620 return NULL;
622 close(fd);
624 /* Now load the library. */
625 *pd = dlopen(path, RTLD_NOW);
626 if (*pd == NULL) {
627 DEBUGF("failed to load %s\n", path);
628 #ifdef WIN32
629 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
630 buf, sizeof buf, NULL);
631 DEBUGF("dlopen(%s): %s\n", path, buf);
632 #else
633 DEBUGF("dlopen(%s): %s\n", path, dlerror());
634 #endif
635 return NULL;
638 hdr = dlsym(*pd, "__header");
639 if (!hdr)
640 hdr = dlsym(*pd, "___header");
642 return hdr; /* maybe NULL if symbol not present */
645 void sim_codec_close(void *pd)
647 dlclose(pd);
650 void *sim_plugin_load(char *plugin, void **pd)
652 void *hdr;
653 char path[MAX_PATH];
654 #ifdef WIN32
655 char buf[MAX_PATH];
656 #endif
658 snprintf(path, sizeof(path), "archos%s", plugin);
660 *pd = NULL;
662 *pd = dlopen(path, RTLD_NOW);
663 if (*pd == NULL) {
664 DEBUGF("failed to load %s\n", plugin);
665 #ifdef WIN32
666 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
667 buf, sizeof(buf), NULL);
668 DEBUGF("dlopen(%s): %s\n", path, buf);
669 #else
670 DEBUGF("dlopen(%s): %s\n", path, dlerror());
671 #endif
672 return NULL;
675 hdr = dlsym(*pd, "__header");
676 if (!hdr)
677 hdr = dlsym(*pd, "___header");
679 return hdr; /* maybe NULL if symbol not present */
682 void sim_plugin_close(void *pd)
684 dlclose(pd);
687 #ifdef WIN32
688 static unsigned old_cp;
690 void debug_exit(void)
692 /* Reset console output codepage */
693 SetConsoleOutputCP(old_cp);
696 void debug_init(void)
698 old_cp = GetConsoleOutputCP();
699 /* Set console output codepage to UTF8. Only works
700 * correctly when the console uses a truetype font. */
701 SetConsoleOutputCP(65001);
702 atexit(debug_exit);
704 #else
705 void debug_init(void)
707 /* nothing to be done */
709 #endif
711 void debugf(const char *fmt, ...)
713 va_list ap;
714 va_start( ap, fmt );
715 vfprintf( stderr, fmt, ap );
716 va_end( ap );
719 void ldebugf(const char* file, int line, const char *fmt, ...)
721 va_list ap;
722 va_start( ap, fmt );
723 fprintf( stderr, "%s:%d ", file, line );
724 vfprintf( stderr, fmt, ap );
725 va_end( ap );
728 /* rockbox off_t may be different from system off_t */
729 int sim_ftruncate(int fd, long length)
731 #ifdef WIN32
732 return _chsize(fd, length);
733 #else
734 return ftruncate(fd, length);
735 #endif