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 *oldpath
, const char *newpath
);
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 static ssize_t
io_trigger_and_wait(int cmd
)
225 void *mythread
= NULL
;
228 if (io
.count
> IO_YIELD_THRESHOLD
||
229 (io
.accum
+= io
.count
) >= IO_YIELD_THRESHOLD
)
231 /* Allow other rockbox threads to run */
233 mythread
= thread_sdl_thread_unlock();
239 result
= read(io
.fd
, io
.buf
, io
.count
);
242 result
= write(io
.fd
, io
.buf
, io
.count
);
246 /* Regain our status as current */
247 if (mythread
!= NULL
)
249 thread_sdl_thread_lock(mythread
);
256 static const char *get_sim_rootdir()
258 if (sim_root_dir
!= NULL
)
260 return SIMULATOR_DEFAULT_ROOT
;
264 MYDIR
*sim_opendir(const char *name
)
269 char buffer
[MAX_PATH
]; /* sufficiently big */
273 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
274 dir
=(DIR_T
*)OPENDIR(buffer
);
278 dir
=(DIR_T
*)OPENDIR(name
);
281 MYDIR
*my
= (MYDIR
*)malloc(sizeof(MYDIR
));
283 my
->name
= (char *)malloc(strlen(name
)+1);
284 strcpy(my
->name
, name
);
288 /* failed open, return NULL */
292 struct sim_dirent
*sim_readdir(MYDIR
*dir
)
294 char buffer
[MAX_PATH
]; /* sufficiently big */
295 static struct sim_dirent secret
;
297 DIRENT_T
*x11
= READDIR(dir
->dir
);
301 return (struct sim_dirent
*)0;
303 strcpy((char *)secret
.d_name
, OS_TO_UTF8(x11
->d_name
));
305 /* build file name */
307 snprintf(buffer
, sizeof(buffer
), "%s/%s", dir
->name
, secret
.d_name
);
309 snprintf(buffer
, sizeof(buffer
), "%s/%s/%s",
310 get_sim_rootdir(), dir
->name
, secret
.d_name
);
312 STAT(buffer
, &s
); /* get info */
314 #define ATTR_DIRECTORY 0x10
316 secret
.attribute
= S_ISDIR(s
.st_mode
)?ATTR_DIRECTORY
:0;
317 secret
.size
= s
.st_size
;
319 tm
= localtime(&(s
.st_mtime
));
320 secret
.wrtdate
= ((tm
->tm_year
- 80) << 9) |
321 ((tm
->tm_mon
+ 1) << 5) |
323 secret
.wrttime
= (tm
->tm_hour
<< 11) |
329 void sim_closedir(MYDIR
*dir
)
337 int sim_open(const char *name
, int o
)
339 char buffer
[MAX_PATH
]; /* sufficiently big */
340 int opts
= rockbox2sim(o
);
343 if (num_openfiles
>= MAX_OPEN_FILES
)
349 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
351 /* debugf("We open the real file '%s'\n", buffer); */
352 if (num_openfiles
< MAX_OPEN_FILES
)
354 ret
= OPEN(buffer
, opts
, 0666);
355 if (ret
>= 0) num_openfiles
++;
360 fprintf(stderr
, "WARNING, bad file name lacks slash: %s\n",
364 ret
= OPEN(name
, opts
, 0666);
371 int sim_close(int fd
)
375 if (ret
== 0) num_openfiles
--;
379 int sim_creat(const char *name
)
382 char buffer
[MAX_PATH
]; /* sufficiently big */
385 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
387 /* debugf("We create the real file '%s'\n", buffer); */
388 return OPEN(buffer
, O_BINARY
| O_WRONLY
| O_CREAT
| O_TRUNC
, 0666);
390 fprintf(stderr
, "WARNING, bad file name lacks slash: %s\n", name
);
393 return OPEN(name
, O_BINARY
| O_WRONLY
| O_CREAT
| O_TRUNC
, 0666);
397 ssize_t
sim_read(int fd
, void *buf
, size_t count
)
401 mutex_lock(&io
.sim_mutex
);
403 /* Setup parameters */
408 result
= io_trigger_and_wait(IO_READ
);
410 mutex_unlock(&io
.sim_mutex
);
415 ssize_t
sim_write(int fd
, const void *buf
, size_t count
)
419 mutex_lock(&io
.sim_mutex
);
425 result
= io_trigger_and_wait(IO_WRITE
);
427 mutex_unlock(&io
.sim_mutex
);
432 int sim_mkdir(const char *name
)
435 return MKDIR(name
, 0777);
437 char buffer
[MAX_PATH
]; /* sufficiently big */
439 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
441 /* debugf("We create the real directory '%s'\n", buffer); */
442 return MKDIR(buffer
, 0777);
446 int sim_rmdir(const char *name
)
451 char buffer
[MAX_PATH
]; /* sufficiently big */
454 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
456 /* debugf("We remove the real directory '%s'\n", buffer); */
457 return RMDIR(buffer
);
463 int sim_remove(const char *name
)
468 char buffer
[MAX_PATH
]; /* sufficiently big */
471 dircache_remove(name
);
475 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
477 /* debugf("We remove the real file '%s'\n", buffer); */
478 return REMOVE(buffer
);
484 int sim_rename(const char *oldpath
, const char* newpath
)
487 return RENAME(oldpath
, newpath
);
489 char buffer1
[MAX_PATH
];
490 char buffer2
[MAX_PATH
];
493 dircache_rename(oldpath
, newpath
);
496 if(oldpath
[0] == '/') {
497 snprintf(buffer1
, sizeof(buffer1
), "%s%s", get_sim_rootdir(),
499 snprintf(buffer2
, sizeof(buffer2
), "%s%s", get_sim_rootdir(),
502 /* debugf("We rename the real file '%s' to '%s'\n", buffer1, buffer2); */
503 return RENAME(buffer1
, buffer2
);
509 /* rockbox off_t may be different from system off_t */
510 long sim_lseek(int fildes
, long offset
, int whence
)
512 return lseek(fildes
, offset
, whence
);
515 long sim_filesize(int fd
)
518 return _filelength(fd
);
522 if (!fstat(fd
, &buf
))
529 void fat_size(IF_MV2(int volume
,) unsigned long* size
, unsigned long* free
)
531 #ifdef HAVE_MULTIVOLUME
533 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
542 long secperclus
, bytespersec
, free_clusters
, num_clusters
;
544 if (GetDiskFreeSpace(NULL
, &secperclus
, &bytespersec
, &free_clusters
,
547 *size
= num_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
549 *free
= free_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
554 if (!statfs(".", &fs
)) {
555 DEBUGF("statfs: bsize=%d blocks=%ld free=%ld\n",
556 (int)fs
.f_bsize
, fs
.f_blocks
, fs
.f_bfree
);
558 *size
= fs
.f_blocks
* (fs
.f_bsize
/ 1024);
560 *free
= fs
.f_bfree
* (fs
.f_bsize
/ 1024);
571 int sim_fsync(int fd
)
582 #define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
583 #define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
584 #define dlclose(_x_) FreeLibrary(_x_)
590 #define TEMP_CODEC_FILE SIMULATOR_DEFAULT_ROOT "/_temp_codec%d.dll"
592 void *sim_codec_load_ram(char* codecptr
, int size
, void **pd
)
604 /* We have to create the dynamic link library file from ram so we
605 can simulate the codec loading. With voice and crossfade,
606 multiple codecs may be loaded at the same time, so we need
607 to find an unused filename */
608 for (codec_count
= 0; codec_count
< 10; codec_count
++)
610 snprintf(path
, sizeof(path
), TEMP_CODEC_FILE
, codec_count
);
612 fd
= OPEN(path
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
, S_IRWXU
);
614 break; /* Created a file ok */
618 DEBUGF("failed to open for write: %s\n", path
);
622 if (write(fd
, codecptr
, size
) != size
) {
623 DEBUGF("write failed");
628 /* Now load the library. */
629 *pd
= dlopen(path
, RTLD_NOW
);
631 DEBUGF("failed to load %s\n", path
);
633 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(), 0,
634 buf
, sizeof buf
, NULL
);
635 DEBUGF("dlopen(%s): %s\n", path
, buf
);
637 DEBUGF("dlopen(%s): %s\n", path
, dlerror());
642 hdr
= dlsym(*pd
, "__header");
644 hdr
= dlsym(*pd
, "___header");
646 return hdr
; /* maybe NULL if symbol not present */
649 void sim_codec_close(void *pd
)
654 void *sim_plugin_load(char *plugin
, void **pd
)
662 snprintf(path
, sizeof(path
), SIMULATOR_DEFAULT_ROOT
"%s", plugin
);
666 *pd
= dlopen(path
, RTLD_NOW
);
668 DEBUGF("failed to load %s\n", plugin
);
670 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(), 0,
671 buf
, sizeof(buf
), NULL
);
672 DEBUGF("dlopen(%s): %s\n", path
, buf
);
674 DEBUGF("dlopen(%s): %s\n", path
, dlerror());
679 hdr
= dlsym(*pd
, "__header");
681 hdr
= dlsym(*pd
, "___header");
683 return hdr
; /* maybe NULL if symbol not present */
686 void sim_plugin_close(void *pd
)
692 static unsigned old_cp
;
694 void debug_exit(void)
696 /* Reset console output codepage */
697 SetConsoleOutputCP(old_cp
);
700 void debug_init(void)
702 old_cp
= GetConsoleOutputCP();
703 /* Set console output codepage to UTF8. Only works
704 * correctly when the console uses a truetype font. */
705 SetConsoleOutputCP(65001);
709 void debug_init(void)
711 /* nothing to be done */
715 void debugf(const char *fmt
, ...)
719 vfprintf( stderr
, fmt
, ap
);
723 void ldebugf(const char* file
, int line
, const char *fmt
, ...)
727 fprintf( stderr
, "%s:%d ", file
, line
);
728 vfprintf( stderr
, fmt
, ap
);
732 /* rockbox off_t may be different from system off_t */
733 int sim_ftruncate(int fd
, long length
)
736 return _chsize(fd
, length
);
738 return ftruncate(fd
, length
);