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 "archos"
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
);
255 static const char *get_sim_rootdir()
257 if (sim_root_dir
!= NULL
)
259 return SIMULATOR_DEFAULT_ROOT
;
262 MYDIR
*sim_opendir(const char *name
)
264 char buffer
[MAX_PATH
]; /* sufficiently big */
270 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
271 dir
=(DIR_T
*)OPENDIR(buffer
);
275 dir
=(DIR_T
*)OPENDIR(name
);
278 MYDIR
*my
= (MYDIR
*)malloc(sizeof(MYDIR
));
280 my
->name
= (char *)strdup(name
);
284 /* failed open, return NULL */
288 struct sim_dirent
*sim_readdir(MYDIR
*dir
)
290 char buffer
[MAX_PATH
]; /* sufficiently big */
291 static struct sim_dirent secret
;
293 DIRENT_T
*x11
= READDIR(dir
->dir
);
297 return (struct sim_dirent
*)0;
299 strcpy((char *)secret
.d_name
, OS_TO_UTF8(x11
->d_name
));
301 /* build file name */
303 snprintf(buffer
, sizeof(buffer
), "%s/%s", dir
->name
, secret
.d_name
);
305 snprintf(buffer
, sizeof(buffer
), "%s/%s/%s",
306 get_sim_rootdir(), dir
->name
, secret
.d_name
);
308 STAT(buffer
, &s
); /* get info */
310 #define ATTR_DIRECTORY 0x10
312 secret
.attribute
= S_ISDIR(s
.st_mode
)?ATTR_DIRECTORY
:0;
313 secret
.size
= s
.st_size
;
315 tm
= localtime(&(s
.st_mtime
));
316 secret
.wrtdate
= ((tm
->tm_year
- 80) << 9) |
317 ((tm
->tm_mon
+ 1) << 5) |
319 secret
.wrttime
= (tm
->tm_hour
<< 11) |
325 void sim_closedir(MYDIR
*dir
)
333 int sim_open(const char *name
, int o
)
335 char buffer
[MAX_PATH
]; /* sufficiently big */
336 int opts
= rockbox2sim(o
);
339 if (num_openfiles
>= MAX_OPEN_FILES
)
345 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
347 /* debugf("We open the real file '%s'\n", buffer); */
348 if (num_openfiles
< MAX_OPEN_FILES
)
350 ret
= OPEN(buffer
, opts
, 0666);
351 if (ret
>= 0) num_openfiles
++;
356 fprintf(stderr
, "WARNING, bad file name lacks slash: %s\n",
360 if (num_openfiles
< MAX_OPEN_FILES
)
362 ret
= OPEN(buffer
, opts
, 0666);
363 if (ret
>= 0) num_openfiles
++;
369 int sim_close(int fd
)
373 if (ret
== 0) num_openfiles
--;
377 int sim_creat(const char *name
)
380 char buffer
[MAX_PATH
]; /* sufficiently big */
383 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
385 /* debugf("We create the real file '%s'\n", buffer); */
386 return OPEN(buffer
, O_BINARY
| O_WRONLY
| O_CREAT
| O_TRUNC
, 0666);
388 fprintf(stderr
, "WARNING, bad file name lacks slash: %s\n", name
);
391 return OPEN(name
, O_BINARY
| O_WRONLY
| O_CREAT
| O_TRUNC
, 0666);
395 ssize_t
sim_read(int fd
, void *buf
, size_t count
)
399 mutex_lock(&io
.sim_mutex
);
401 /* Setup parameters */
406 result
= io_trigger_and_wait(IO_READ
);
408 mutex_unlock(&io
.sim_mutex
);
413 ssize_t
sim_write(int fd
, const void *buf
, size_t count
)
417 mutex_lock(&io
.sim_mutex
);
423 result
= io_trigger_and_wait(IO_WRITE
);
425 mutex_unlock(&io
.sim_mutex
);
430 int sim_mkdir(const char *name
)
433 return MKDIR(name
, 0777);
435 char buffer
[MAX_PATH
]; /* sufficiently big */
437 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
439 /* debugf("We create the real directory '%s'\n", buffer); */
440 return MKDIR(buffer
, 0777);
444 int sim_rmdir(const char *name
)
449 char buffer
[MAX_PATH
]; /* sufficiently big */
452 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
454 /* debugf("We remove the real directory '%s'\n", buffer); */
455 return RMDIR(buffer
);
461 int sim_remove(const char *name
)
466 char buffer
[MAX_PATH
]; /* sufficiently big */
469 dircache_remove(name
);
473 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
475 /* debugf("We remove the real file '%s'\n", buffer); */
476 return REMOVE(buffer
);
482 int sim_rename(const char *oldpath
, const char* newpath
)
485 return RENAME(oldpath
, newpath
);
487 char buffer1
[MAX_PATH
];
488 char buffer2
[MAX_PATH
];
491 dircache_rename(oldpath
, newpath
);
494 if(oldpath
[0] == '/') {
495 snprintf(buffer1
, sizeof(buffer1
), "%s%s", get_sim_rootdir(),
497 snprintf(buffer2
, sizeof(buffer2
), "%s%s", get_sim_rootdir(),
500 /* debugf("We rename the real file '%s' to '%s'\n", buffer1, buffer2); */
501 return RENAME(buffer1
, buffer2
);
507 /* rockbox off_t may be different from system off_t */
508 long sim_lseek(int fildes
, long offset
, int whence
)
510 return lseek(fildes
, offset
, whence
);
513 long sim_filesize(int fd
)
516 return _filelength(fd
);
520 if (!fstat(fd
, &buf
))
527 void fat_size(IF_MV2(int volume
,) unsigned long* size
, unsigned long* free
)
529 #ifdef HAVE_MULTIVOLUME
531 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
540 long secperclus
, bytespersec
, free_clusters
, num_clusters
;
542 if (GetDiskFreeSpace(NULL
, &secperclus
, &bytespersec
, &free_clusters
,
545 *size
= num_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
547 *free
= free_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
552 if (!statfs(".", &fs
)) {
553 DEBUGF("statfs: bsize=%d blocks=%ld free=%ld\n",
554 (int)fs
.f_bsize
, fs
.f_blocks
, fs
.f_bfree
);
556 *size
= fs
.f_blocks
* (fs
.f_bsize
/ 1024);
558 *free
= fs
.f_bfree
* (fs
.f_bsize
/ 1024);
569 int sim_fsync(int fd
)
580 #define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
581 #define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
582 #define dlclose(_x_) FreeLibrary(_x_)
588 #define TEMP_CODEC_FILE "archos/_temp_codec%d.dll"
590 void *sim_codec_load_ram(char* codecptr
, int size
, void **pd
)
602 /* We have to create the dynamic link library file from ram so we
603 can simulate the codec loading. With voice and crossfade,
604 multiple codecs may be loaded at the same time, so we need
605 to find an unused filename */
606 for (codec_count
= 0; codec_count
< 10; codec_count
++)
608 snprintf(path
, sizeof(path
), TEMP_CODEC_FILE
, codec_count
);
610 fd
= OPEN(path
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
, S_IRWXU
);
612 break; /* Created a file ok */
616 DEBUGF("failed to open for write: %s\n", path
);
620 if (write(fd
, codecptr
, size
) != size
) {
621 DEBUGF("write failed");
626 /* Now load the library. */
627 *pd
= dlopen(path
, RTLD_NOW
);
629 DEBUGF("failed to load %s\n", path
);
631 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(), 0,
632 buf
, sizeof buf
, NULL
);
633 DEBUGF("dlopen(%s): %s\n", path
, buf
);
635 DEBUGF("dlopen(%s): %s\n", path
, dlerror());
640 hdr
= dlsym(*pd
, "__header");
642 hdr
= dlsym(*pd
, "___header");
644 return hdr
; /* maybe NULL if symbol not present */
647 void sim_codec_close(void *pd
)
652 void *sim_plugin_load(char *plugin
, void **pd
)
660 snprintf(path
, sizeof(path
), "archos%s", plugin
);
664 *pd
= dlopen(path
, RTLD_NOW
);
666 DEBUGF("failed to load %s\n", plugin
);
668 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(), 0,
669 buf
, sizeof(buf
), NULL
);
670 DEBUGF("dlopen(%s): %s\n", path
, buf
);
672 DEBUGF("dlopen(%s): %s\n", path
, dlerror());
677 hdr
= dlsym(*pd
, "__header");
679 hdr
= dlsym(*pd
, "___header");
681 return hdr
; /* maybe NULL if symbol not present */
684 void sim_plugin_close(void *pd
)
690 static unsigned old_cp
;
692 void debug_exit(void)
694 /* Reset console output codepage */
695 SetConsoleOutputCP(old_cp
);
698 void debug_init(void)
700 old_cp
= GetConsoleOutputCP();
701 /* Set console output codepage to UTF8. Only works
702 * correctly when the console uses a truetype font. */
703 SetConsoleOutputCP(65001);
707 void debug_init(void)
709 /* nothing to be done */
713 void debugf(const char *fmt
, ...)
717 vfprintf( stderr
, fmt
, ap
);
721 void ldebugf(const char* file
, int line
, const char *fmt
, ...)
725 fprintf( stderr
, "%s:%d ", file
, line
);
726 vfprintf( stderr
, fmt
, ap
);
730 /* rockbox off_t may be different from system off_t */
731 int sim_ftruncate(int fd
, long length
)
734 return _chsize(fd
, length
);
736 return ftruncate(fd
, length
);