remove some really old and out of date code... (drawing API changed about 3 times...
[Rockbox.git] / uisimulator / common / io.c
blob822a43b63dd795126e5c7b23e239f2e06e74b781
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdarg.h>
24 #include <sys/stat.h>
25 #include <time.h>
26 #ifdef __FreeBSD__
27 #include <sys/param.h>
28 #include <sys/mount.h>
29 #elif defined(__APPLE__)
30 #include <sys/param.h>
31 #include <sys/mount.h>
32 #elif !defined(WIN32)
33 #include <sys/vfs.h>
34 #endif
36 #ifdef WIN32
37 #include <windows.h>
38 #endif
40 #ifndef _MSC_VER
41 #include <dirent.h>
42 #include <unistd.h>
43 #else
44 #include "dir-win32.h"
45 #endif
47 #define MAX_PATH 260
48 #define MAX_OPEN_FILES 11
50 #include <fcntl.h>
51 #include <SDL.h>
52 #include <SDL_thread.h>
53 #include "thread.h"
54 #include "kernel.h"
55 #include "debug.h"
56 #include "config.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. */
63 #ifndef O_BINARY
64 #define O_BINARY 0
65 #endif
67 /* Unicode compatibility for win32 */
68 #if defined __MINGW32__
69 /* Rockbox unicode functions */
70 extern const unsigned char* utf8decode(const unsigned char *utf8,
71 unsigned short *ucs);
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;
83 while (*utf8)
84 utf8 = utf8decode(utf8, ucs++);
86 *ucs = 0;
87 return buffer;
89 static unsigned char *ucs2_to_utf8(const wchar_t *ucs, unsigned char *buffer)
91 unsigned char *utf8 = buffer;
93 while (*ucs)
94 utf8 = utf8encode(*ucs++, utf8);
96 *utf8 = 0;
97 return buffer;
100 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
101 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
102 #define DIR_T _WDIR
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)
122 #define DIR_T DIR
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__ */
139 #ifdef HAVE_DIRCACHE
140 void dircache_remove(const char *name);
141 void dircache_rename(const char *oldpath, const char *newpath);
142 #endif
145 #define SIMULATOR_DEFAULT_ROOT "archos"
146 extern const char *sim_root_dir;
148 static int num_openfiles = 0;
150 struct sim_dirent {
151 unsigned char d_name[MAX_PATH];
152 int attribute;
153 long size;
154 long startcluster;
155 unsigned short wrtdate; /* Last write date */
156 unsigned short wrttime; /* Last write time */
159 struct dirstruct {
160 void *dir; /* actually a DIR* dir */
161 char *name;
162 } SIM_DIR;
164 struct mydir {
165 DIR_T *dir;
166 char *name;
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;
176 if(opt & 1)
177 newopt |= O_WRONLY;
178 if(opt & 2)
179 newopt |= O_RDWR;
180 if(opt & 4)
181 newopt |= O_CREAT;
182 if(opt & 8)
183 newopt |= O_APPEND;
184 if(opt & 0x10)
185 newopt |= O_TRUNC;
187 return newopt;
189 #endif
191 /** Simulator I/O engine routines **/
192 #define IO_YIELD_THRESHOLD 512
194 enum
196 IO_READ,
197 IO_WRITE,
200 struct sim_io
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;
213 int ata_init(void)
215 /* Initialize the rockbox kernel objects on a rockbox thread */
216 mutex_init(&io.sim_mutex);
217 io.accum = 0;
218 return 1;
221 static ssize_t io_trigger_and_wait(int cmd)
223 void *mythread = NULL;
224 ssize_t result;
226 if (io.count > IO_YIELD_THRESHOLD ||
227 (io.accum += io.count) >= IO_YIELD_THRESHOLD)
229 /* Allow other rockbox threads to run */
230 io.accum = 0;
231 mythread = thread_sdl_thread_unlock();
234 switch (cmd)
236 case IO_READ:
237 result = read(io.fd, io.buf, io.count);
238 break;
239 case IO_WRITE:
240 result = write(io.fd, io.buf, io.count);
241 break;
244 /* Regain our status as current */
245 if (mythread != NULL)
247 thread_sdl_thread_lock(mythread);
250 return result;
253 static const char *get_sim_rootdir()
255 if (sim_root_dir != NULL)
256 return sim_root_dir;
257 return SIMULATOR_DEFAULT_ROOT;
260 MYDIR *sim_opendir(const char *name)
262 char buffer[MAX_PATH]; /* sufficiently big */
263 DIR_T *dir;
265 #ifndef __PCTOOL__
266 if(name[0] == '/')
268 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
269 dir=(DIR_T *)OPENDIR(buffer);
271 else
272 #endif
273 dir=(DIR_T *)OPENDIR(name);
275 if(dir) {
276 MYDIR *my = (MYDIR *)malloc(sizeof(MYDIR));
277 my->dir = dir;
278 my->name = (char *)strdup(name);
280 return my;
282 /* failed open, return NULL */
283 return (MYDIR *)0;
286 struct sim_dirent *sim_readdir(MYDIR *dir)
288 char buffer[MAX_PATH]; /* sufficiently big */
289 static struct sim_dirent secret;
290 STAT_T s;
291 DIRENT_T *x11 = READDIR(dir->dir);
292 struct tm* tm;
294 if(!x11)
295 return (struct sim_dirent *)0;
297 strcpy((char *)secret.d_name, OS_TO_UTF8(x11->d_name));
299 /* build file name */
300 #ifdef __PCTOOL__
301 snprintf(buffer, sizeof(buffer), "%s/%s", dir->name, secret.d_name);
302 #else
303 snprintf(buffer, sizeof(buffer), "%s/%s/%s",
304 get_sim_rootdir(), dir->name, secret.d_name);
305 #endif
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) |
316 tm->tm_mday;
317 secret.wrttime = (tm->tm_hour << 11) |
318 (tm->tm_min << 5) |
319 (tm->tm_sec >> 1);
320 return &secret;
323 void sim_closedir(MYDIR *dir)
325 free(dir->name);
326 CLOSEDIR(dir->dir);
328 free(dir);
331 int sim_open(const char *name, int o)
333 char buffer[MAX_PATH]; /* sufficiently big */
334 int opts = rockbox2sim(o);
335 int ret;
337 if (num_openfiles >= MAX_OPEN_FILES)
338 return -2;
340 #ifndef __PCTOOL__
341 if(name[0] == '/')
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++;
350 return ret;
354 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n",
355 name);
356 return -1;
357 #else
358 if (num_openfiles < MAX_OPEN_FILES)
360 ret = OPEN(buffer, opts, 0666);
361 if (ret >= 0) num_openfiles++;
362 return ret;
364 #endif
367 int sim_close(int fd)
369 int ret;
370 ret = CLOSE(fd);
371 if (ret == 0) num_openfiles--;
372 return ret;
375 int sim_creat(const char *name)
377 #ifndef __PCTOOL__
378 char buffer[MAX_PATH]; /* sufficiently big */
379 if(name[0] == '/')
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);
387 return -1;
388 #else
389 return OPEN(name, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666);
390 #endif
393 ssize_t sim_read(int fd, void *buf, size_t count)
395 ssize_t result;
397 mutex_lock(&io.sim_mutex);
399 /* Setup parameters */
400 io.fd = fd;
401 io.buf = buf;
402 io.count = count;
404 result = io_trigger_and_wait(IO_READ);
406 mutex_unlock(&io.sim_mutex);
408 return result;
411 ssize_t sim_write(int fd, const void *buf, size_t count)
413 ssize_t result;
415 mutex_lock(&io.sim_mutex);
417 io.fd = fd;
418 io.buf = (void*)buf;
419 io.count = count;
421 result = io_trigger_and_wait(IO_WRITE);
423 mutex_unlock(&io.sim_mutex);
425 return result;
428 int sim_mkdir(const char *name)
430 #ifdef __PCTOOL__
431 return MKDIR(name, 0777);
432 #else
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);
439 #endif
442 int sim_rmdir(const char *name)
444 #ifdef __PCTOOL__
445 return RMDIR(name);
446 #else
447 char buffer[MAX_PATH]; /* sufficiently big */
448 if(name[0] == '/')
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);
455 return RMDIR(name);
456 #endif
459 int sim_remove(const char *name)
461 #ifdef __PCTOOL__
462 return REMOVE(name);
463 #else
464 char buffer[MAX_PATH]; /* sufficiently big */
466 #ifdef HAVE_DIRCACHE
467 dircache_remove(name);
468 #endif
470 if(name[0] == '/') {
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);
476 return REMOVE(name);
477 #endif
480 int sim_rename(const char *oldpath, const char* newpath)
482 #ifdef __PCTOOL__
483 return RENAME(oldpath, newpath);
484 #else
485 char buffer1[MAX_PATH];
486 char buffer2[MAX_PATH];
488 #ifdef HAVE_DIRCACHE
489 dircache_rename(oldpath, newpath);
490 #endif
492 if(oldpath[0] == '/') {
493 snprintf(buffer1, sizeof(buffer1), "%s%s", get_sim_rootdir(),
494 oldpath);
495 snprintf(buffer2, sizeof(buffer2), "%s%s", get_sim_rootdir(),
496 newpath);
498 debugf("We rename the real file '%s' to '%s'\n", buffer1, buffer2);
499 return RENAME(buffer1, buffer2);
501 return -1;
502 #endif
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)
513 #ifdef WIN32
514 return _filelength(fd);
515 #else
516 struct stat buf;
518 if (!fstat(fd, &buf))
519 return buf.st_size;
520 else
521 return -1;
522 #endif
525 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
527 #ifdef HAVE_MULTIVOLUME
528 if (volume != 0) {
529 debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",
530 volume);
532 if (size) *size = 0;
533 if (free) *free = 0;
534 return;
536 #endif
538 #ifdef WIN32
539 long secperclus, bytespersec, free_clusters, num_clusters;
541 if (GetDiskFreeSpace(NULL, &secperclus, &bytespersec, &free_clusters,
542 &num_clusters)) {
543 if (size)
544 *size = num_clusters * secperclus / 2 * (bytespersec / 512);
545 if (free)
546 *free = free_clusters * secperclus / 2 * (bytespersec / 512);
548 #else
549 struct statfs fs;
551 if (!statfs(".", &fs)) {
552 DEBUGF("statfs: bsize=%d blocks=%ld free=%ld\n",
553 (int)fs.f_bsize, fs.f_blocks, fs.f_bfree);
554 if (size)
555 *size = fs.f_blocks * (fs.f_bsize / 1024);
556 if (free)
557 *free = fs.f_bfree * (fs.f_bsize / 1024);
559 #endif
560 else {
561 if (size)
562 *size = 0;
563 if (free)
564 *free = 0;
568 int sim_fsync(int fd)
570 #ifdef WIN32
571 return _commit(fd);
572 #else
573 return fsync(fd);
574 #endif
577 #ifdef WIN32
578 /* sim-win32 */
579 #define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
580 #define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
581 #define dlclose(_x_) FreeLibrary(_x_)
582 #else
583 /* sim-x11 */
584 #include <dlfcn.h>
585 #endif
587 #define TEMP_CODEC_FILE "archos/_temp_codec%d.dll"
589 void *sim_codec_load_ram(char* codecptr, int size, void **pd)
591 void *hdr;
592 char path[MAX_PATH];
593 int fd;
594 int codec_count;
595 #ifdef WIN32
596 char buf[MAX_PATH];
597 #endif
599 *pd = NULL;
601 /* We have to create the dynamic link library file from ram so we
602 can simulate the codec loading. With voice and crossfade,
603 multiple codecs may be loaded at the same time, so we need
604 to find an unused filename */
605 for (codec_count = 0; codec_count < 10; codec_count++)
607 snprintf(path, sizeof(path), TEMP_CODEC_FILE, codec_count);
609 fd = OPEN(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRWXU);
610 if (fd >= 0)
611 break; /* Created a file ok */
613 if (fd < 0)
615 DEBUGF("failed to open for write: %s\n", path);
616 return NULL;
619 if (write(fd, codecptr, size) != size) {
620 DEBUGF("write failed");
621 return NULL;
623 close(fd);
625 /* Now load the library. */
626 *pd = dlopen(path, RTLD_NOW);
627 if (*pd == NULL) {
628 DEBUGF("failed to load %s\n", path);
629 #ifdef WIN32
630 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
631 buf, sizeof buf, NULL);
632 DEBUGF("dlopen(%s): %s\n", path, buf);
633 #else
634 DEBUGF("dlopen(%s): %s\n", path, dlerror());
635 #endif
636 return NULL;
639 hdr = dlsym(*pd, "__header");
640 if (!hdr)
641 hdr = dlsym(*pd, "___header");
643 return hdr; /* maybe NULL if symbol not present */
646 void sim_codec_close(void *pd)
648 dlclose(pd);
651 void *sim_plugin_load(char *plugin, void **pd)
653 void *hdr;
654 char path[MAX_PATH];
655 #ifdef WIN32
656 char buf[MAX_PATH];
657 #endif
659 snprintf(path, sizeof(path), "archos%s", plugin);
661 *pd = NULL;
663 *pd = dlopen(path, RTLD_NOW);
664 if (*pd == NULL) {
665 DEBUGF("failed to load %s\n", plugin);
666 #ifdef WIN32
667 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
668 buf, sizeof(buf), NULL);
669 DEBUGF("dlopen(%s): %s\n", path, buf);
670 #else
671 DEBUGF("dlopen(%s): %s\n", path, dlerror());
672 #endif
673 return NULL;
676 hdr = dlsym(*pd, "__header");
677 if (!hdr)
678 hdr = dlsym(*pd, "___header");
680 return hdr; /* maybe NULL if symbol not present */
683 void sim_plugin_close(void *pd)
685 dlclose(pd);
688 #ifdef WIN32
689 static unsigned old_cp;
691 void debug_exit(void)
693 /* Reset console output codepage */
694 SetConsoleOutputCP(old_cp);
697 void debug_init(void)
699 old_cp = GetConsoleOutputCP();
700 /* Set console output codepage to UTF8. Only works
701 * correctly when the console uses a truetype font. */
702 SetConsoleOutputCP(65001);
703 atexit(debug_exit);
705 #else
706 void debug_init(void)
708 /* nothing to be done */
710 #endif
712 void debugf(const char *fmt, ...)
714 va_list ap;
715 va_start( ap, fmt );
716 vfprintf( stderr, fmt, ap );
717 va_end( ap );
720 void ldebugf(const char* file, int line, const char *fmt, ...)
722 va_list ap;
723 va_start( ap, fmt );
724 fprintf( stderr, "%s:%d ", file, line );
725 vfprintf( stderr, fmt, ap );
726 va_end( ap );
729 /* rockbox off_t may be different from system off_t */
730 int sim_ftruncate(int fd, long length)
732 #ifdef WIN32
733 return _chsize(fd, length);
734 #else
735 return ftruncate(fd, length);
736 #endif