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"
48 #define MAX_OPEN_FILES 11
52 #include <SDL_thread.h>
57 #include "ata.h" /* for IF_MV2 et al. */
58 #include "thread-sdl.h"
61 /* Windows (and potentially other OSes) distinguish binary and text files.
62 * Define a dummy for the others. */
67 /* Unicode compatibility for win32 */
68 #if defined __MINGW32__
69 /* Rockbox unicode functions */
70 extern const unsigned char* utf8decode(const unsigned char *utf8
,
72 extern unsigned char* utf8encode(unsigned long ucs
, unsigned char *utf8
);
74 /* Static buffers for the conversion results. This isn't thread safe,
75 * but it's sufficient for rockbox. */
76 static unsigned char convbuf1
[3*MAX_PATH
];
77 static unsigned char convbuf2
[3*MAX_PATH
];
79 static wchar_t* utf8_to_ucs2(const unsigned char *utf8
, void *buffer
)
81 wchar_t *ucs
= buffer
;
84 utf8
= utf8decode(utf8
, ucs
++);
89 static unsigned char *ucs2_to_utf8(const wchar_t *ucs
, unsigned char *buffer
)
91 unsigned char *utf8
= buffer
;
94 utf8
= utf8encode(*ucs
++, utf8
);
100 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
101 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
103 #define DIRENT_T struct _wdirent
104 #define STAT_T struct _stat
105 extern int _wmkdir(const wchar_t*);
106 extern int _wrmdir(const wchar_t*);
107 #define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
108 #define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
109 #define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
110 #define READDIR(a) (_wreaddir)(a)
111 #define CLOSEDIR(a) (_wclosedir)(a)
112 #define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
113 #define OPEN(a,b,c) (_wopen)(UTF8_TO_OS(a),b,c)
114 #define CLOSE(a) (close)(a)
115 #define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
116 #define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
118 #else /* !__MINGW32__ */
120 #define UTF8_TO_OS(a) (a)
121 #define OS_TO_UTF8(a) (a)
123 #define DIRENT_T struct dirent
124 #define STAT_T struct stat
125 #define MKDIR(a,b) (mkdir)(a,b)
126 #define RMDIR(a) (rmdir)(a)
127 #define OPENDIR(a) (opendir)(a)
128 #define READDIR(a) (readdir)(a)
129 #define CLOSEDIR(a) (closedir)(a)
130 #define STAT(a,b) (stat)(a,b)
131 #define OPEN(a,b,c) (open)(a,b,c)
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 *oldpath
, const char *newpath
);
145 #define SIMULATOR_DEFAULT_ROOT "archos"
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 static ssize_t
io_trigger_and_wait(int cmd
)
223 void *mythread
= NULL
;
226 if (io
.count
> IO_YIELD_THRESHOLD
||
227 (io
.accum
+= io
.count
) >= IO_YIELD_THRESHOLD
)
229 /* Allow other rockbox threads to run */
231 mythread
= thread_sdl_thread_unlock();
237 result
= read(io
.fd
, io
.buf
, io
.count
);
240 result
= write(io
.fd
, io
.buf
, io
.count
);
244 /* Regain our status as current */
245 if (mythread
!= NULL
)
247 thread_sdl_thread_lock(mythread
);
253 static const char *get_sim_rootdir()
255 if (sim_root_dir
!= NULL
)
257 return SIMULATOR_DEFAULT_ROOT
;
260 MYDIR
*sim_opendir(const char *name
)
262 char buffer
[MAX_PATH
]; /* sufficiently big */
268 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
269 dir
=(DIR_T
*)OPENDIR(buffer
);
273 dir
=(DIR_T
*)OPENDIR(name
);
276 MYDIR
*my
= (MYDIR
*)malloc(sizeof(MYDIR
));
278 my
->name
= (char *)strdup(name
);
282 /* failed open, return NULL */
286 struct sim_dirent
*sim_readdir(MYDIR
*dir
)
288 char buffer
[MAX_PATH
]; /* sufficiently big */
289 static struct sim_dirent secret
;
291 DIRENT_T
*x11
= READDIR(dir
->dir
);
295 return (struct sim_dirent
*)0;
297 strcpy((char *)secret
.d_name
, OS_TO_UTF8(x11
->d_name
));
299 /* build file name */
301 snprintf(buffer
, sizeof(buffer
), "%s/%s", dir
->name
, secret
.d_name
);
303 snprintf(buffer
, sizeof(buffer
), "%s/%s/%s",
304 get_sim_rootdir(), dir
->name
, secret
.d_name
);
306 STAT(buffer
, &s
); /* get info */
308 #define ATTR_DIRECTORY 0x10
310 secret
.attribute
= S_ISDIR(s
.st_mode
)?ATTR_DIRECTORY
:0;
311 secret
.size
= s
.st_size
;
313 tm
= localtime(&(s
.st_mtime
));
314 secret
.wrtdate
= ((tm
->tm_year
- 80) << 9) |
315 ((tm
->tm_mon
+ 1) << 5) |
317 secret
.wrttime
= (tm
->tm_hour
<< 11) |
323 void sim_closedir(MYDIR
*dir
)
331 int sim_open(const char *name
, int o
)
333 char buffer
[MAX_PATH
]; /* sufficiently big */
334 int opts
= rockbox2sim(o
);
337 if (num_openfiles
>= MAX_OPEN_FILES
)
343 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
345 /* debugf("We open the real file '%s'\n", buffer); */
346 if (num_openfiles
< MAX_OPEN_FILES
)
348 ret
= OPEN(buffer
, opts
, 0666);
349 if (ret
>= 0) num_openfiles
++;
354 fprintf(stderr
, "WARNING, bad file name lacks slash: %s\n",
358 if (num_openfiles
< MAX_OPEN_FILES
)
360 ret
= OPEN(buffer
, opts
, 0666);
361 if (ret
>= 0) num_openfiles
++;
367 int sim_close(int fd
)
371 if (ret
== 0) num_openfiles
--;
375 int sim_creat(const char *name
)
378 char buffer
[MAX_PATH
]; /* sufficiently big */
381 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
383 /* debugf("We create the real file '%s'\n", buffer); */
384 return OPEN(buffer
, O_BINARY
| O_WRONLY
| O_CREAT
| O_TRUNC
, 0666);
386 fprintf(stderr
, "WARNING, bad file name lacks slash: %s\n", name
);
389 return OPEN(name
, O_BINARY
| O_WRONLY
| O_CREAT
| O_TRUNC
, 0666);
393 ssize_t
sim_read(int fd
, void *buf
, size_t count
)
397 mutex_lock(&io
.sim_mutex
);
399 /* Setup parameters */
404 result
= io_trigger_and_wait(IO_READ
);
406 mutex_unlock(&io
.sim_mutex
);
411 ssize_t
sim_write(int fd
, const void *buf
, size_t count
)
415 mutex_lock(&io
.sim_mutex
);
421 result
= io_trigger_and_wait(IO_WRITE
);
423 mutex_unlock(&io
.sim_mutex
);
428 int sim_mkdir(const char *name
)
431 return MKDIR(name
, 0777);
433 char buffer
[MAX_PATH
]; /* sufficiently big */
435 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
437 /* debugf("We create the real directory '%s'\n", buffer); */
438 return MKDIR(buffer
, 0777);
442 int sim_rmdir(const char *name
)
447 char buffer
[MAX_PATH
]; /* sufficiently big */
450 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
452 /* debugf("We remove the real directory '%s'\n", buffer); */
453 return RMDIR(buffer
);
459 int sim_remove(const char *name
)
464 char buffer
[MAX_PATH
]; /* sufficiently big */
467 dircache_remove(name
);
471 snprintf(buffer
, sizeof(buffer
), "%s%s", get_sim_rootdir(), name
);
473 /* debugf("We remove the real file '%s'\n", buffer); */
474 return REMOVE(buffer
);
480 int sim_rename(const char *oldpath
, const char* newpath
)
483 return RENAME(oldpath
, newpath
);
485 char buffer1
[MAX_PATH
];
486 char buffer2
[MAX_PATH
];
489 dircache_rename(oldpath
, newpath
);
492 if(oldpath
[0] == '/') {
493 snprintf(buffer1
, sizeof(buffer1
), "%s%s", get_sim_rootdir(),
495 snprintf(buffer2
, sizeof(buffer2
), "%s%s", get_sim_rootdir(),
498 /* debugf("We rename the real file '%s' to '%s'\n", buffer1, buffer2); */
499 return RENAME(buffer1
, buffer2
);
505 /* rockbox off_t may be different from system off_t */
506 long sim_lseek(int fildes
, long offset
, int whence
)
508 return lseek(fildes
, offset
, whence
);
511 long sim_filesize(int fd
)
514 return _filelength(fd
);
518 if (!fstat(fd
, &buf
))
525 void fat_size(IF_MV2(int volume
,) unsigned long* size
, unsigned long* free
)
527 #ifdef HAVE_MULTIVOLUME
529 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
538 long secperclus
, bytespersec
, free_clusters
, num_clusters
;
540 if (GetDiskFreeSpace(NULL
, &secperclus
, &bytespersec
, &free_clusters
,
543 *size
= num_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
545 *free
= free_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
550 if (!statfs(".", &fs
)) {
551 DEBUGF("statfs: bsize=%d blocks=%ld free=%ld\n",
552 (int)fs
.f_bsize
, fs
.f_blocks
, fs
.f_bfree
);
554 *size
= fs
.f_blocks
* (fs
.f_bsize
/ 1024);
556 *free
= fs
.f_bfree
* (fs
.f_bsize
/ 1024);
567 int sim_fsync(int fd
)
578 #define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
579 #define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
580 #define dlclose(_x_) FreeLibrary(_x_)
586 #define TEMP_CODEC_FILE "archos/_temp_codec%d.dll"
588 void *sim_codec_load_ram(char* codecptr
, int size
, void **pd
)
600 /* We have to create the dynamic link library file from ram so we
601 can simulate the codec loading. With voice and crossfade,
602 multiple codecs may be loaded at the same time, so we need
603 to find an unused filename */
604 for (codec_count
= 0; codec_count
< 10; codec_count
++)
606 snprintf(path
, sizeof(path
), TEMP_CODEC_FILE
, codec_count
);
608 fd
= OPEN(path
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
, S_IRWXU
);
610 break; /* Created a file ok */
614 DEBUGF("failed to open for write: %s\n", path
);
618 if (write(fd
, codecptr
, size
) != size
) {
619 DEBUGF("write failed");
624 /* Now load the library. */
625 *pd
= dlopen(path
, RTLD_NOW
);
627 DEBUGF("failed to load %s\n", path
);
629 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(), 0,
630 buf
, sizeof buf
, NULL
);
631 DEBUGF("dlopen(%s): %s\n", path
, buf
);
633 DEBUGF("dlopen(%s): %s\n", path
, dlerror());
638 hdr
= dlsym(*pd
, "__header");
640 hdr
= dlsym(*pd
, "___header");
642 return hdr
; /* maybe NULL if symbol not present */
645 void sim_codec_close(void *pd
)
650 void *sim_plugin_load(char *plugin
, void **pd
)
658 snprintf(path
, sizeof(path
), "archos%s", plugin
);
662 *pd
= dlopen(path
, RTLD_NOW
);
664 DEBUGF("failed to load %s\n", plugin
);
666 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(), 0,
667 buf
, sizeof(buf
), NULL
);
668 DEBUGF("dlopen(%s): %s\n", path
, buf
);
670 DEBUGF("dlopen(%s): %s\n", path
, dlerror());
675 hdr
= dlsym(*pd
, "__header");
677 hdr
= dlsym(*pd
, "___header");
679 return hdr
; /* maybe NULL if symbol not present */
682 void sim_plugin_close(void *pd
)
688 static unsigned old_cp
;
690 void debug_exit(void)
692 /* Reset console output codepage */
693 SetConsoleOutputCP(old_cp
);
696 void debug_init(void)
698 old_cp
= GetConsoleOutputCP();
699 /* Set console output codepage to UTF8. Only works
700 * correctly when the console uses a truetype font. */
701 SetConsoleOutputCP(65001);
705 void debug_init(void)
707 /* nothing to be done */
711 void debugf(const char *fmt
, ...)
715 vfprintf( stderr
, fmt
, ap
);
719 void ldebugf(const char* file
, int line
, const char *fmt
, ...)
723 fprintf( stderr
, "%s:%d ", file
, line
);
724 vfprintf( stderr
, fmt
, ap
);
728 /* rockbox off_t may be different from system off_t */
729 int sim_ftruncate(int fd
, long length
)
732 return _chsize(fd
, length
);
734 return ftruncate(fd
, length
);