1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
29 #include <sys/param.h>
30 #include <sys/mount.h>
31 #elif defined(__APPLE__)
32 #include <sys/param.h>
33 #include <sys/mount.h>
46 #include "dir-win32.h"
50 #define MAX_OPEN_FILES 11
54 #include <SDL_thread.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. */
69 /* Unicode compatibility for win32 */
70 #if defined __MINGW32__
71 /* Rockbox unicode functions */
72 extern const unsigned char* utf8decode(const unsigned char *utf8
,
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
;
86 utf8
= utf8decode(utf8
, ucs
++);
91 static unsigned char *ucs2_to_utf8(const wchar_t *ucs
, unsigned char *buffer
)
93 unsigned char *utf8
= buffer
;
96 utf8
= utf8encode(*ucs
++, utf8
);
102 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
103 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
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)
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__ */
142 void dircache_remove(const char *name
);
143 void dircache_rename(const char *oldname
, const char *newname
);
147 #define SIMULATOR_DEFAULT_ROOT "simdisk"
148 extern const char *sim_root_dir
;
150 static int num_openfiles
= 0;
153 unsigned char d_name
[MAX_PATH
];
157 unsigned short wrtdate
; /* Last write date */
158 unsigned short wrttime
; /* Last write time */
162 void *dir
; /* actually a DIR* dir */
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
;
193 /** Simulator I/O engine routines **/
194 #define IO_YIELD_THRESHOLD 512
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
;
217 /* Initialize the rockbox kernel objects on a rockbox thread */
218 mutex_init(&io
.sim_mutex
);
223 int ata_spinup_time(void)
228 static ssize_t
io_trigger_and_wait(int cmd
)
230 void *mythread
= NULL
;
233 if (io
.count
> IO_YIELD_THRESHOLD
||
234 (io
.accum
+= io
.count
) >= IO_YIELD_THRESHOLD
)
236 /* Allow other rockbox threads to run */
238 mythread
= thread_sdl_thread_unlock();
244 result
= read(io
.fd
, io
.buf
, io
.count
);
247 result
= write(io
.fd
, io
.buf
, io
.count
);
251 /* Regain our status as current */
252 if (mythread
!= NULL
)
254 thread_sdl_thread_lock(mythread
);
261 static const char *get_sim_pathname(const char *name
)
263 static char buffer
[MAX_PATH
]; /* sufficiently big */
267 snprintf(buffer
, sizeof(buffer
), "%s%s",
268 sim_root_dir
!= NULL
? sim_root_dir
: SIMULATOR_DEFAULT_ROOT
, name
);
271 fprintf(stderr
, "WARNING, bad file name lacks slash: %s\n", name
);
275 #define get_sim_pathname(name) name
278 MYDIR
*sim_opendir(const char *name
)
282 dir
= (DIR_T
*) OPENDIR(get_sim_pathname(name
));
286 MYDIR
*my
= (MYDIR
*)malloc(sizeof(MYDIR
));
288 my
->name
= (char *)malloc(strlen(name
)+1);
289 strcpy(my
->name
, name
);
293 /* failed open, return NULL */
297 struct sim_dirent
*sim_readdir(MYDIR
*dir
)
299 char buffer
[MAX_PATH
]; /* sufficiently big */
300 static struct sim_dirent secret
;
302 DIRENT_T
*x11
= READDIR(dir
->dir
);
306 return (struct sim_dirent
*)0;
308 strcpy((char *)secret
.d_name
, OS_TO_UTF8(x11
->d_name
));
310 /* build file name */
311 snprintf(buffer
, sizeof(buffer
), "%s/%s",
312 get_sim_pathname(dir
->name
), secret
.d_name
);
313 STAT(buffer
, &s
); /* get info */
315 #define ATTR_DIRECTORY 0x10
317 secret
.attribute
= S_ISDIR(s
.st_mode
)?ATTR_DIRECTORY
:0;
318 secret
.size
= s
.st_size
;
320 tm
= localtime(&(s
.st_mtime
));
321 secret
.wrtdate
= ((tm
->tm_year
- 80) << 9) |
322 ((tm
->tm_mon
+ 1) << 5) |
324 secret
.wrttime
= (tm
->tm_hour
<< 11) |
330 void sim_closedir(MYDIR
*dir
)
338 int sim_open(const char *name
, int o
)
340 int opts
= rockbox2sim(o
);
343 if (num_openfiles
>= MAX_OPEN_FILES
)
346 ret
= OPEN(get_sim_pathname(name
), opts
, 0666);
352 int sim_close(int fd
)
361 int sim_creat(const char *name
)
363 return OPEN(get_sim_pathname(name
), O_BINARY
| O_WRONLY
| O_CREAT
| O_TRUNC
, 0666);
366 ssize_t
sim_read(int fd
, void *buf
, size_t count
)
370 mutex_lock(&io
.sim_mutex
);
372 /* Setup parameters */
377 result
= io_trigger_and_wait(IO_READ
);
379 mutex_unlock(&io
.sim_mutex
);
384 ssize_t
sim_write(int fd
, const void *buf
, size_t count
)
388 mutex_lock(&io
.sim_mutex
);
394 result
= io_trigger_and_wait(IO_WRITE
);
396 mutex_unlock(&io
.sim_mutex
);
401 int sim_mkdir(const char *name
)
403 return MKDIR(get_sim_pathname(name
), 0777);
406 int sim_rmdir(const char *name
)
408 return RMDIR(get_sim_pathname(name
));
411 int sim_remove(const char *name
)
414 dircache_remove(name
);
416 return REMOVE(get_sim_pathname(name
));
419 int sim_rename(const char *oldname
, const char *newname
)
421 char sim_old
[MAX_PATH
];
422 char sim_new
[MAX_PATH
];
424 dircache_rename(oldname
, newname
);
426 // This is needed as get_sim_pathname() has a static buffer
427 strncpy(sim_old
, get_sim_pathname(oldname
), MAX_PATH
);
428 strncpy(sim_new
, get_sim_pathname(newname
), MAX_PATH
);
429 return RENAME(sim_old
, sim_new
);
432 /* rockbox off_t may be different from system off_t */
433 long sim_lseek(int fildes
, long offset
, int whence
)
435 return lseek(fildes
, offset
, whence
);
438 long sim_filesize(int fd
)
441 return _filelength(fd
);
445 if (!fstat(fd
, &buf
))
452 void fat_size(IF_MV2(int volume
,) unsigned long* size
, unsigned long* free
)
454 #ifdef HAVE_MULTIVOLUME
456 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
465 long secperclus
, bytespersec
, free_clusters
, num_clusters
;
467 if (GetDiskFreeSpace(NULL
, &secperclus
, &bytespersec
, &free_clusters
,
470 *size
= num_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
472 *free
= free_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
477 if (!statfs(".", &fs
)) {
478 DEBUGF("statfs: bsize=%d blocks=%ld free=%ld\n",
479 (int)fs
.f_bsize
, fs
.f_blocks
, fs
.f_bfree
);
481 *size
= fs
.f_blocks
* (fs
.f_bsize
/ 1024);
483 *free
= fs
.f_bfree
* (fs
.f_bsize
/ 1024);
494 int sim_fsync(int fd
)
505 #define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
506 #define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
507 #define dlclose(_x_) FreeLibrary(_x_)
513 void *sim_codec_load_ram(char* codecptr
, int size
, void **pd
)
526 /* We have to create the dynamic link library file from ram so we
527 can simulate the codec loading. With voice and crossfade,
528 multiple codecs may be loaded at the same time, so we need
529 to find an unused filename */
530 for (codec_count
= 0; codec_count
< 10; codec_count
++)
532 snprintf(name
, sizeof(name
), "/_temp_codec%d.dll", codec_count
);
533 snprintf(path
, sizeof(path
), "%s", get_sim_pathname(name
));
534 fd
= OPEN(path
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
, S_IRWXU
);
536 break; /* Created a file ok */
540 DEBUGF("failed to open for write: %s\n", path
);
544 if (write(fd
, codecptr
, size
) != size
)
546 DEBUGF("write failed");
551 /* Now load the library. */
552 *pd
= dlopen(path
, RTLD_NOW
);
555 DEBUGF("failed to load %s\n", path
);
557 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(), 0,
558 buf
, sizeof buf
, NULL
);
559 DEBUGF("dlopen(%s): %s\n", path
, buf
);
561 DEBUGF("dlopen(%s): %s\n", path
, dlerror());
566 hdr
= dlsym(*pd
, "__header");
568 hdr
= dlsym(*pd
, "___header");
570 return hdr
; /* maybe NULL if symbol not present */
573 void sim_codec_close(void *pd
)
578 void *sim_plugin_load(char *plugin
, void **pd
)
586 snprintf(path
, sizeof(path
), "%s", get_sim_pathname(plugin
));
590 *pd
= dlopen(path
, RTLD_NOW
);
592 DEBUGF("failed to load %s\n", plugin
);
594 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(), 0,
595 buf
, sizeof(buf
), NULL
);
596 DEBUGF("dlopen(%s): %s\n", path
, buf
);
598 DEBUGF("dlopen(%s): %s\n", path
, dlerror());
603 hdr
= dlsym(*pd
, "__header");
605 hdr
= dlsym(*pd
, "___header");
607 return hdr
; /* maybe NULL if symbol not present */
610 void sim_plugin_close(void *pd
)
616 static unsigned old_cp
;
618 void debug_exit(void)
620 /* Reset console output codepage */
621 SetConsoleOutputCP(old_cp
);
624 void debug_init(void)
626 old_cp
= GetConsoleOutputCP();
627 /* Set console output codepage to UTF8. Only works
628 * correctly when the console uses a truetype font. */
629 SetConsoleOutputCP(65001);
633 void debug_init(void)
635 /* nothing to be done */
639 void debugf(const char *fmt
, ...)
643 vfprintf( stderr
, fmt
, ap
);
647 void ldebugf(const char* file
, int line
, const char *fmt
, ...)
651 fprintf( stderr
, "%s:%d ", file
, line
);
652 vfprintf( stderr
, fmt
, ap
);
656 /* rockbox off_t may be different from system off_t */
657 int sim_ftruncate(int fd
, long length
)
660 return _chsize(fd
, length
);
662 return ftruncate(fd
, length
);