1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
27 #include <sys/param.h>
28 #include <sys/mount.h>
29 #elif defined(__APPLE__)
30 #include <sys/param.h>
31 #include <sys/mount.h>
44 #include "dir-win32.h"
51 #include <SDL_thread.h>
56 #include "ata.h" /* for IF_MV2 et al. */
58 /* Windows (and potentially other OSes) distinguish binary and text files.
59 * Define a dummy for the others. */
64 /* Unicode compatibility for win32 */
65 #if defined __MINGW32__
66 /* Rockbox unicode functions */
67 extern const unsigned char* utf8decode(const unsigned char *utf8
,
69 extern unsigned char* utf8encode(unsigned long ucs
, unsigned char *utf8
);
71 /* Static buffers for the conversion results. This isn't thread safe,
72 * but it's sufficient for rockbox. */
73 static unsigned char convbuf1
[3*MAX_PATH
];
74 static unsigned char convbuf2
[3*MAX_PATH
];
76 static wchar_t* utf8_to_ucs2(const unsigned char *utf8
, void *buffer
)
78 wchar_t *ucs
= buffer
;
81 utf8
= utf8decode(utf8
, ucs
++);
86 static unsigned char *ucs2_to_utf8(const wchar_t *ucs
, unsigned char *buffer
)
88 unsigned char *utf8
= buffer
;
91 utf8
= utf8encode(*ucs
++, utf8
);
97 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
98 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
100 #define DIRENT_T struct _wdirent
101 #define STAT_T struct _stat
102 extern int _wmkdir(const wchar_t*);
103 extern int _wrmdir(const wchar_t*);
104 #define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
105 #define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
106 #define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
107 #define READDIR(a) (_wreaddir)(a)
108 #define CLOSEDIR(a) (_wclosedir)(a)
109 #define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
110 #define OPEN(a,b,c) (_wopen)(UTF8_TO_OS(a),b,c)
111 #define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
112 #define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
114 #else /* !__MINGW32__ */
116 #define UTF8_TO_OS(a) (a)
117 #define OS_TO_UTF8(a) (a)
119 #define DIRENT_T struct dirent
120 #define STAT_T struct stat
121 #define MKDIR(a,b) (mkdir)(a,b)
122 #define RMDIR(a) (rmdir)(a)
123 #define OPENDIR(a) (opendir)(a)
124 #define READDIR(a) (readdir)(a)
125 #define CLOSEDIR(a) (closedir)(a)
126 #define STAT(a,b) (stat)(a,b)
127 #define OPEN(a,b,c) (open)(a,b,c)
128 #define REMOVE(a) (remove)(a)
129 #define RENAME(a,b) (rename)(a,b)
131 #endif /* !__MINGW32__ */
135 void dircache_remove(const char *name
);
136 void dircache_rename(const char *oldpath
, const char *newpath
);
139 #define SIMULATOR_ARCHOS_ROOT "archos"
142 unsigned char d_name
[MAX_PATH
];
146 unsigned short wrtdate
; /* Last write date */
147 unsigned short wrttime
; /* Last write time */
151 void *dir
; /* actually a DIR* dir */
160 typedef struct mydir MYDIR
;
162 #if 1 /* maybe this needs disabling for MSVC... */
163 static unsigned int rockbox2sim(int opt
)
165 int newopt
= O_BINARY
;
182 /** Simulator I/O engine routines **/
194 SDL_mutex
*m
; /* Mutex for condition */
195 SDL_cond
*c
; /* Condition for synchronizing threads */
196 SDL_Thread
*t
; /* The I/O thread */
197 struct mutex sim_mutex
; /* Rockbox mutex */
198 volatile int cmd
; /* The command to perform */
199 volatile int ready
; /* I/O ready flag - 1= ready */
200 volatile int fd
; /* The file to read/write */
201 void* volatile buf
; /* The buffer to read/write */
202 volatile size_t count
; /* Number of bytes to read/write */
203 ssize_t result
; /* Result of operation */
206 static struct sim_io io
;
208 static int io_thread(void *data
)
212 io
.ready
= 1; /* Indication mutex has been locked */
216 SDL_CondWait(io
.c
, io
.m
); /* unlock mutex and wait */
221 io
.result
= read(io
.fd
, io
.buf
, io
.count
);
225 io
.result
= write(io
.fd
, io
.buf
, io
.count
);
229 SDL_UnlockMutex(io
.m
);
237 bool sim_io_init(void)
241 io
.m
= SDL_CreateMutex();
244 fprintf(stderr
, "Failed to create IO mutex\n");
248 io
.c
= SDL_CreateCond();
251 fprintf(stderr
, "Failed to create IO cond\n");
255 io
.t
= SDL_CreateThread(io_thread
, NULL
);
258 fprintf(stderr
, "Failed to create IO thread\n");
262 /* Wait for IO thread to lock mutex */
266 /* Wait for it to unlock */
268 /* Free it for another thread */
269 SDL_UnlockMutex(io
.m
);
276 /* Initialize the rockbox kernel objects on a rockbox thread */
277 mutex_init(&io
.sim_mutex
);
281 void sim_io_shutdown(void)
287 SDL_CondSignal(io
.c
);
288 SDL_UnlockMutex(io
.m
);
290 SDL_WaitThread(io
.t
, NULL
);
292 SDL_DestroyMutex(io
.m
);
293 SDL_DestroyCond(io
.c
);
296 static void io_trigger_and_wait(int cmd
)
298 /* Lock mutex before setting up new params and signaling condition */
304 /* Get thread started */
305 SDL_CondSignal(io
.c
);
308 SDL_UnlockMutex(io
.m
);
310 /* Wait for IO to complete */
315 MYDIR
*sim_opendir(const char *name
)
317 char buffer
[MAX_PATH
]; /* sufficiently big */
323 snprintf(buffer
, sizeof(buffer
), "%s%s", SIMULATOR_ARCHOS_ROOT
, name
);
324 dir
=(DIR_T
*)OPENDIR(buffer
);
328 dir
=(DIR_T
*)OPENDIR(name
);
331 MYDIR
*my
= (MYDIR
*)malloc(sizeof(MYDIR
));
333 my
->name
= (char *)strdup(name
);
337 /* failed open, return NULL */
341 struct sim_dirent
*sim_readdir(MYDIR
*dir
)
343 char buffer
[512]; /* sufficiently big */
344 static struct sim_dirent secret
;
346 DIRENT_T
*x11
= READDIR(dir
->dir
);
350 return (struct sim_dirent
*)0;
352 strcpy((char *)secret
.d_name
, OS_TO_UTF8(x11
->d_name
));
354 /* build file name */
356 snprintf(buffer
, sizeof(buffer
), "%s/%s", dir
->name
, secret
.d_name
);
358 snprintf(buffer
, sizeof(buffer
), SIMULATOR_ARCHOS_ROOT
"%s/%s",
359 dir
->name
, secret
.d_name
);
361 STAT(buffer
, &s
); /* get info */
363 #define ATTR_DIRECTORY 0x10
365 secret
.attribute
= S_ISDIR(s
.st_mode
)?ATTR_DIRECTORY
:0;
366 secret
.size
= s
.st_size
;
368 tm
= localtime(&(s
.st_mtime
));
369 secret
.wrtdate
= ((tm
->tm_year
- 80) << 9) |
370 ((tm
->tm_mon
+ 1) << 5) |
372 secret
.wrttime
= (tm
->tm_hour
<< 11) |
378 void sim_closedir(MYDIR
*dir
)
386 int sim_open(const char *name
, int o
)
388 char buffer
[MAX_PATH
]; /* sufficiently big */
389 int opts
= rockbox2sim(o
);
394 snprintf(buffer
, sizeof(buffer
), "%s%s", SIMULATOR_ARCHOS_ROOT
, name
);
396 debugf("We open the real file '%s'\n", buffer
);
397 return OPEN(buffer
, opts
, 0666);
400 fprintf(stderr
, "WARNING, bad file name lacks slash: %s\n",
404 return OPEN(name
, opts
, 0666);
409 int sim_creat(const char *name
)
412 char buffer
[MAX_PATH
]; /* sufficiently big */
415 snprintf(buffer
, sizeof(buffer
), "%s%s", SIMULATOR_ARCHOS_ROOT
, name
);
417 debugf("We create the real file '%s'\n", buffer
);
418 return OPEN(buffer
, O_BINARY
| O_WRONLY
| O_CREAT
| O_TRUNC
, 0666);
420 fprintf(stderr
, "WARNING, bad file name lacks slash: %s\n", name
);
423 return OPEN(name
, O_BINARY
| O_WRONLY
| O_CREAT
| O_TRUNC
, 0666);
427 ssize_t
sim_read(int fd
, void *buf
, size_t count
)
431 mutex_lock(&io
.sim_mutex
);
433 /* Setup parameters */
438 io_trigger_and_wait(IO_READ
);
442 mutex_unlock(&io
.sim_mutex
);
447 ssize_t
sim_write(int fd
, const void *buf
, size_t count
)
451 mutex_lock(&io
.sim_mutex
);
457 io_trigger_and_wait(IO_WRITE
);
461 mutex_unlock(&io
.sim_mutex
);
466 int sim_mkdir(const char *name
)
469 return MKDIR(name
, 0777);
471 char buffer
[MAX_PATH
]; /* sufficiently big */
473 snprintf(buffer
, sizeof(buffer
), "%s%s", SIMULATOR_ARCHOS_ROOT
, name
);
475 debugf("We create the real directory '%s'\n", buffer
);
476 return MKDIR(buffer
, 0777);
480 int sim_rmdir(const char *name
)
485 char buffer
[MAX_PATH
]; /* sufficiently big */
488 snprintf(buffer
, sizeof(buffer
), "%s%s", SIMULATOR_ARCHOS_ROOT
, name
);
490 debugf("We remove the real directory '%s'\n", buffer
);
491 return RMDIR(buffer
);
497 int sim_remove(const char *name
)
502 char buffer
[MAX_PATH
]; /* sufficiently big */
505 dircache_remove(name
);
509 snprintf(buffer
, sizeof(buffer
), "%s%s", SIMULATOR_ARCHOS_ROOT
, name
);
511 debugf("We remove the real file '%s'\n", buffer
);
512 return REMOVE(buffer
);
518 int sim_rename(const char *oldpath
, const char* newpath
)
521 return RENAME(oldpath
, newpath
);
523 char buffer1
[MAX_PATH
];
524 char buffer2
[MAX_PATH
];
527 dircache_rename(oldpath
, newpath
);
530 if(oldpath
[0] == '/') {
531 snprintf(buffer1
, sizeof(buffer1
), "%s%s", SIMULATOR_ARCHOS_ROOT
,
533 snprintf(buffer2
, sizeof(buffer2
), "%s%s", SIMULATOR_ARCHOS_ROOT
,
536 debugf("We rename the real file '%s' to '%s'\n", buffer1
, buffer2
);
537 return RENAME(buffer1
, buffer2
);
543 /* rockbox off_t may be different from system off_t */
544 long sim_lseek(int fildes
, long offset
, int whence
)
546 return lseek(fildes
, offset
, whence
);
549 long sim_filesize(int fd
)
552 return _filelength(fd
);
556 if (!fstat(fd
, &buf
))
563 void fat_size(IF_MV2(int volume
,) unsigned long* size
, unsigned long* free
)
565 #ifdef HAVE_MULTIVOLUME
567 debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",
577 long secperclus
, bytespersec
, free_clusters
, num_clusters
;
579 if (GetDiskFreeSpace(NULL
, &secperclus
, &bytespersec
, &free_clusters
,
582 *size
= num_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
584 *free
= free_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
589 if (!statfs(".", &fs
)) {
590 DEBUGF("statfs: bsize=%d blocks=%ld free=%ld\n",
591 (int)fs
.f_bsize
, fs
.f_blocks
, fs
.f_bfree
);
593 *size
= fs
.f_blocks
* (fs
.f_bsize
/ 1024);
595 *free
= fs
.f_bfree
* (fs
.f_bsize
/ 1024);
606 int sim_fsync(int fd
)
617 #define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
618 #define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
619 #define dlclose(_x_) FreeLibrary(_x_)
625 #define TEMP_CODEC_FILE "archos/_temp_codec%d.dll"
627 void *sim_codec_load_ram(char* codecptr
, int size
,
628 void* ptr2
, int bufwrap
, void **pd
)
641 /* We have to create the dynamic link library file from ram so we
642 can simulate the codec loading. With voice and crossfade,
643 multiple codecs may be loaded at the same time, so we need
644 to find an unused filename */
645 for (codec_count
= 0; codec_count
< 10; codec_count
++)
647 snprintf(path
, sizeof(path
), TEMP_CODEC_FILE
, codec_count
);
649 fd
= OPEN(path
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
, S_IRWXU
);
651 break; /* Created a file ok */
655 DEBUGF("failed to open for write: %s\n", path
);
662 copy_n
= bufwrap
< size
? bufwrap
: size
;
663 if (write(fd
, codecptr
, copy_n
) != copy_n
) {
664 DEBUGF("write failed");
669 if (write(fd
, ptr2
, size
) != size
) {
670 DEBUGF("write failed [2]");
676 /* Now load the library. */
677 *pd
= dlopen(path
, RTLD_NOW
);
679 DEBUGF("failed to load %s\n", path
);
681 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(), 0,
682 buf
, sizeof buf
, NULL
);
683 DEBUGF("dlopen(%s): %s\n", path
, buf
);
685 DEBUGF("dlopen(%s): %s\n", path
, dlerror());
690 hdr
= dlsym(*pd
, "__header");
692 hdr
= dlsym(*pd
, "___header");
694 return hdr
; /* maybe NULL if symbol not present */
697 void sim_codec_close(void *pd
)
702 void *sim_plugin_load(char *plugin
, void **pd
)
710 snprintf(path
, sizeof(path
), "archos%s", plugin
);
714 *pd
= dlopen(path
, RTLD_NOW
);
716 DEBUGF("failed to load %s\n", plugin
);
718 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(), 0,
719 buf
, sizeof(buf
), NULL
);
720 DEBUGF("dlopen(%s): %s\n", path
, buf
);
722 DEBUGF("dlopen(%s): %s\n", path
, dlerror());
727 hdr
= dlsym(*pd
, "__header");
729 hdr
= dlsym(*pd
, "___header");
731 return hdr
; /* maybe NULL if symbol not present */
734 void sim_plugin_close(void *pd
)
740 static unsigned old_cp
;
742 void debug_exit(void)
744 /* Reset console output codepage */
745 SetConsoleOutputCP(old_cp
);
748 void debug_init(void)
750 old_cp
= GetConsoleOutputCP();
751 /* Set console output codepage to UTF8. Only works
752 * correctly when the console uses a truetype font. */
753 SetConsoleOutputCP(65001);
757 void debug_init(void)
759 /* nothing to be done */
763 void debugf(const char *fmt
, ...)
767 vfprintf( stderr
, fmt
, ap
);
771 void ldebugf(const char* file
, int line
, const char *fmt
, ...)
775 fprintf( stderr
, "%s:%d ", file
, line
);
776 vfprintf( stderr
, fmt
, ap
);
780 /* rockbox off_t may be different from system off_t */
781 int sim_ftruncate(int fd
, long length
)
784 return _chsize(fd
, length
);
786 return ftruncate(fd
, length
);