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/statvfs.h>
40 #include "dir-win32.h"
44 #define MAX_OPEN_FILES 11
48 #include <SDL_thread.h>
53 #include "ata.h" /* for IF_MV2 et al. */
54 #include "thread-sdl.h"
57 /* Windows (and potentially other OSes) distinguish binary and text files.
58 * Define a dummy for the others. */
63 /* Unicode compatibility for win32 */
64 #if defined __MINGW32__
65 /* Rockbox unicode functions */
66 extern const unsigned char* utf8decode(const unsigned char *utf8
,
68 extern unsigned char* utf8encode(unsigned long ucs
, unsigned char *utf8
);
70 /* Static buffers for the conversion results. This isn't thread safe,
71 * but it's sufficient for rockbox. */
72 static unsigned char convbuf1
[3*MAX_PATH
];
73 static unsigned char convbuf2
[3*MAX_PATH
];
75 static wchar_t* utf8_to_ucs2(const unsigned char *utf8
, void *buffer
)
77 wchar_t *ucs
= buffer
;
80 utf8
= utf8decode(utf8
, ucs
++);
85 static unsigned char *ucs2_to_utf8(const wchar_t *ucs
, unsigned char *buffer
)
87 unsigned char *utf8
= buffer
;
90 utf8
= utf8encode(*ucs
++, utf8
);
96 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
97 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
99 #define DIRENT_T struct _wdirent
100 #define STAT_T struct _stat
101 extern int _wmkdir(const wchar_t*);
102 extern int _wrmdir(const wchar_t*);
103 #define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
104 #define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
105 #define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
106 #define READDIR(a) (_wreaddir)(a)
107 #define CLOSEDIR(a) (_wclosedir)(a)
108 #define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
109 /* empty variable parameter list doesn't work for variadic macros,
110 * so pretend the second parameter is variable too */
111 #define OPEN(a,...) (_wopen)(UTF8_TO_OS(a), __VA_ARGS__)
112 #define CLOSE(a) (close)(a)
113 #define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
114 #define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
116 #else /* !__MINGW32__ */
118 #define UTF8_TO_OS(a) (a)
119 #define OS_TO_UTF8(a) (a)
121 #define DIRENT_T struct dirent
122 #define STAT_T struct stat
123 #define MKDIR(a,b) (mkdir)(a,b)
124 #define RMDIR(a) (rmdir)(a)
125 #define OPENDIR(a) (opendir)(a)
126 #define READDIR(a) (readdir)(a)
127 #define CLOSEDIR(a) (closedir)(a)
128 #define STAT(a,b) (stat)(a,b)
129 /* empty variable parameter list doesn't work for variadic macros,
130 * so pretend the second parameter is variable too */
131 #define OPEN(a, ...) (open)(a, __VA_ARGS__)
132 #define CLOSE(x) (close)(x)
133 #define REMOVE(a) (remove)(a)
134 #define RENAME(a,b) (rename)(a,b)
136 #endif /* !__MINGW32__ */
140 void dircache_remove(const char *name
);
141 void dircache_rename(const char *oldname
, const char *newname
);
145 #define SIMULATOR_DEFAULT_ROOT "simdisk"
146 extern const char *sim_root_dir
;
148 static int num_openfiles
= 0;
151 unsigned char d_name
[MAX_PATH
];
155 unsigned short wrtdate
; /* Last write date */
156 unsigned short wrttime
; /* Last write time */
160 void *dir
; /* actually a DIR* dir */
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
;
191 /** Simulator I/O engine routines **/
192 #define IO_YIELD_THRESHOLD 512
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
;
215 /* Initialize the rockbox kernel objects on a rockbox thread */
216 mutex_init(&io
.sim_mutex
);
221 int ata_spinup_time(void)
226 static ssize_t
io_trigger_and_wait(int cmd
)
228 void *mythread
= NULL
;
231 if (io
.count
> IO_YIELD_THRESHOLD
||
232 (io
.accum
+= io
.count
) >= IO_YIELD_THRESHOLD
)
234 /* Allow other rockbox threads to run */
236 mythread
= thread_sdl_thread_unlock();
242 result
= read(io
.fd
, io
.buf
, io
.count
);
245 result
= write(io
.fd
, io
.buf
, io
.count
);
249 /* Regain our status as current */
250 if (mythread
!= NULL
)
252 thread_sdl_thread_lock(mythread
);
259 static const char *get_sim_pathname(const char *name
)
261 static char buffer
[MAX_PATH
]; /* sufficiently big */
265 snprintf(buffer
, sizeof(buffer
), "%s%s",
266 sim_root_dir
!= NULL
? sim_root_dir
: SIMULATOR_DEFAULT_ROOT
, name
);
269 fprintf(stderr
, "WARNING, bad file name lacks slash: %s\n", name
);
273 #define get_sim_pathname(name) name
276 MYDIR
*sim_opendir(const char *name
)
280 dir
= (DIR_T
*) OPENDIR(get_sim_pathname(name
));
284 MYDIR
*my
= (MYDIR
*)malloc(sizeof(MYDIR
));
286 my
->name
= (char *)malloc(strlen(name
)+1);
287 strcpy(my
->name
, name
);
291 /* failed open, return NULL */
295 struct sim_dirent
*sim_readdir(MYDIR
*dir
)
297 char buffer
[MAX_PATH
]; /* sufficiently big */
298 static struct sim_dirent secret
;
300 DIRENT_T
*x11
= READDIR(dir
->dir
);
304 return (struct sim_dirent
*)0;
306 strcpy((char *)secret
.d_name
, OS_TO_UTF8(x11
->d_name
));
308 /* build file name */
309 snprintf(buffer
, sizeof(buffer
), "%s/%s",
310 get_sim_pathname(dir
->name
), secret
.d_name
);
311 STAT(buffer
, &s
); /* get info */
313 #define ATTR_DIRECTORY 0x10
315 secret
.attribute
= S_ISDIR(s
.st_mode
)?ATTR_DIRECTORY
:0;
316 secret
.size
= s
.st_size
;
318 tm
= localtime(&(s
.st_mtime
));
319 secret
.wrtdate
= ((tm
->tm_year
- 80) << 9) |
320 ((tm
->tm_mon
+ 1) << 5) |
322 secret
.wrttime
= (tm
->tm_hour
<< 11) |
328 void sim_closedir(MYDIR
*dir
)
336 int sim_open(const char *name
, int o
, ...)
338 int opts
= rockbox2sim(o
);
340 if (num_openfiles
>= MAX_OPEN_FILES
)
347 ret
= OPEN(get_sim_pathname(name
), opts
, va_arg(ap
, mode_t
));
351 ret
= OPEN(get_sim_pathname(name
), opts
);
358 int sim_close(int fd
)
367 int sim_creat(const char *name
, mode_t mode
)
369 return OPEN(get_sim_pathname(name
), O_BINARY
| O_WRONLY
| O_CREAT
| O_TRUNC
, mode
);
372 ssize_t
sim_read(int fd
, void *buf
, size_t count
)
376 mutex_lock(&io
.sim_mutex
);
378 /* Setup parameters */
383 result
= io_trigger_and_wait(IO_READ
);
385 mutex_unlock(&io
.sim_mutex
);
390 ssize_t
sim_write(int fd
, const void *buf
, size_t count
)
394 mutex_lock(&io
.sim_mutex
);
400 result
= io_trigger_and_wait(IO_WRITE
);
402 mutex_unlock(&io
.sim_mutex
);
407 int sim_mkdir(const char *name
)
409 return MKDIR(get_sim_pathname(name
), 0777);
412 int sim_rmdir(const char *name
)
414 return RMDIR(get_sim_pathname(name
));
417 int sim_remove(const char *name
)
420 dircache_remove(name
);
422 return REMOVE(get_sim_pathname(name
));
425 int sim_rename(const char *oldname
, const char *newname
)
427 char sim_old
[MAX_PATH
];
428 char sim_new
[MAX_PATH
];
430 dircache_rename(oldname
, newname
);
432 // This is needed as get_sim_pathname() has a static buffer
433 strncpy(sim_old
, get_sim_pathname(oldname
), MAX_PATH
);
434 strncpy(sim_new
, get_sim_pathname(newname
), MAX_PATH
);
435 return RENAME(sim_old
, sim_new
);
438 /* rockbox off_t may be different from system off_t */
439 long sim_lseek(int fildes
, long offset
, int whence
)
441 return lseek(fildes
, offset
, whence
);
444 long sim_filesize(int fd
)
447 return _filelength(fd
);
451 if (!fstat(fd
, &buf
))
458 void fat_size(IF_MV2(int volume
,) unsigned long* size
, unsigned long* free
)
460 #ifdef HAVE_MULTIVOLUME
462 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
471 long secperclus
, bytespersec
, free_clusters
, num_clusters
;
473 if (GetDiskFreeSpace(NULL
, &secperclus
, &bytespersec
, &free_clusters
,
476 *size
= num_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
478 *free
= free_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
483 if (!statvfs(".", &vfs
)) {
484 DEBUGF("statvfs: frsize=%d blocks=%ld free=%ld\n",
485 (int)vfs
.f_frsize
, (long)vfs
.f_blocks
, (long)vfs
.f_bfree
);
487 *size
= vfs
.f_blocks
/ 2 * (vfs
.f_frsize
/ 512);
489 *free
= vfs
.f_bfree
/ 2 * (vfs
.f_frsize
/ 512);
500 int sim_fsync(int fd
)
511 #define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
512 #define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
513 #define dlclose(_x_) FreeLibrary(_x_)
519 void *sim_codec_load_ram(char* codecptr
, int size
, void **pd
)
532 /* We have to create the dynamic link library file from ram so we
533 can simulate the codec loading. With voice and crossfade,
534 multiple codecs may be loaded at the same time, so we need
535 to find an unused filename */
536 for (codec_count
= 0; codec_count
< 10; codec_count
++)
538 snprintf(name
, sizeof(name
), "/_temp_codec%d.dll", codec_count
);
539 snprintf(path
, sizeof(path
), "%s", get_sim_pathname(name
));
540 fd
= OPEN(path
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
, S_IRWXU
);
542 break; /* Created a file ok */
546 DEBUGF("failed to open for write: %s\n", path
);
550 if (write(fd
, codecptr
, size
) != size
)
552 DEBUGF("write failed");
557 /* Now load the library. */
558 *pd
= dlopen(path
, RTLD_NOW
);
561 DEBUGF("failed to load %s\n", path
);
563 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(), 0,
564 buf
, sizeof buf
, NULL
);
565 DEBUGF("dlopen(%s): %s\n", path
, buf
);
567 DEBUGF("dlopen(%s): %s\n", path
, dlerror());
572 hdr
= dlsym(*pd
, "__header");
574 hdr
= dlsym(*pd
, "___header");
576 return hdr
; /* maybe NULL if symbol not present */
579 void sim_codec_close(void *pd
)
584 void *sim_plugin_load(char *plugin
, void **pd
)
592 snprintf(path
, sizeof(path
), "%s", get_sim_pathname(plugin
));
596 *pd
= dlopen(path
, RTLD_NOW
);
598 DEBUGF("failed to load %s\n", plugin
);
600 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(), 0,
601 buf
, sizeof(buf
), NULL
);
602 DEBUGF("dlopen(%s): %s\n", path
, buf
);
604 DEBUGF("dlopen(%s): %s\n", path
, dlerror());
609 hdr
= dlsym(*pd
, "__header");
611 hdr
= dlsym(*pd
, "___header");
613 return hdr
; /* maybe NULL if symbol not present */
616 void sim_plugin_close(void *pd
)
622 static unsigned old_cp
;
624 void debug_exit(void)
626 /* Reset console output codepage */
627 SetConsoleOutputCP(old_cp
);
630 void debug_init(void)
632 old_cp
= GetConsoleOutputCP();
633 /* Set console output codepage to UTF8. Only works
634 * correctly when the console uses a truetype font. */
635 SetConsoleOutputCP(65001);
639 void debug_init(void)
641 /* nothing to be done */
645 void debugf(const char *fmt
, ...)
649 vfprintf( stderr
, fmt
, ap
);
653 void ldebugf(const char* file
, int line
, const char *fmt
, ...)
657 fprintf( stderr
, "%s:%d ", file
, line
);
658 vfprintf( stderr
, fmt
, ap
);
662 /* rockbox off_t may be different from system off_t */
663 int sim_ftruncate(int fd
, long length
)
666 return _chsize(fd
, length
);
668 return ftruncate(fd
, length
);