Core commit. Compile and run on the OpenPandora
[mupen64plus-pandora.git] / source / mupen64plus-core / src / osal / files_win32.c
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *   Mupen64plus-core - osal/files_win32.c                                 *
3  *   Mupen64Plus homepage: http://code.google.com/p/mupen64plus/           *
4  *   Copyright (C) 2009 Richard Goedeken                                   *
5  *                                                                         *
6  *   This program is free software; you can redistribute it and/or modify  *
7  *   it under the terms of the GNU General Public License as published by  *
8  *   the Free Software Foundation; either version 2 of the License, or     *
9  *   (at your option) any later version.                                   *
10  *                                                                         *
11  *   This program is distributed in the hope that it will be useful,       * 
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14  *   GNU General Public License for more details.                          *
15  *                                                                         *
16  *   You should have received a copy of the GNU General Public License     *
17  *   along with this program; if not, write to the                         *
18  *   Free Software Foundation, Inc.,                                       *
19  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
20  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21                        
22 /* This file contains the definitions for the unix-specific file handling
23  * functions
24  */
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <direct.h>
32 #include <shlobj.h>
33
34 #include "files.h"
35 #include "api/m64p_types.h"
36 #include "api/callbacks.h"
37
38 /* definitions for system directories to search when looking for shared data files */
39 #if defined(SHAREDIR)
40   #define XSTR(S) STR(S) /* this wacky preprocessor thing is necessary to generate a quote-enclosed */
41   #define STR(S) #S      /* copy of the SHAREDIR macro, which is defined by the makefile via gcc -DSHAREDIR="..." */
42   static const int   datasearchdirs = 2;
43   static const char *datasearchpath[2] = { XSTR(SHAREDIR), ".\\" };
44   #undef STR
45   #undef XSTR
46 #else
47   static const int   datasearchdirs = 1;
48   static const char *datasearchpath[1] = { ".\\" };
49 #endif
50
51 /* local functions */
52 static int search_dir_file(char *destpath, const char *path, const char *filename)
53 {
54     struct _stat fileinfo;
55
56     /* sanity check to start */
57     if (destpath == NULL || path == NULL || filename == NULL)
58         return 1;
59
60     /* build the full filepath */
61     strcpy(destpath, path);
62     if (destpath[strlen(destpath)-1] != '\\')
63         strcat(destpath, "\\");
64     strcat(destpath, filename);
65
66     /* test for a valid file */
67     if (_stat(destpath, &fileinfo) != 0)
68         return 2;
69     if ((fileinfo.st_mode & _S_IFREG) == 0)
70         return 3;
71
72     /* success - file exists and is a regular file */
73     return 0;
74 }
75
76 /* global functions */
77
78 int osal_mkdirp(const char *dirpath, int mode)
79 {
80     char *mypath, *currpath, *lastchar;
81     struct _stat fileinfo;
82
83     // Create a copy of the path, so we can modify it
84     mypath = currpath = _strdup(dirpath);
85     if (mypath == NULL)
86         return 1;
87
88         // if the directory path ends with a separator, remove it
89         lastchar = mypath + strlen(mypath) - 1;
90         if (strchr(OSAL_DIR_SEPARATORS, *lastchar) != NULL)
91                 *lastchar = 0;
92
93     // Terminate quickly if the path already exists
94     if (_stat(mypath, &fileinfo) == 0 && (fileinfo.st_mode & _S_IFDIR))
95                 goto goodexit;
96
97     while ((currpath = strpbrk(currpath + 1, OSAL_DIR_SEPARATORS)) != NULL)
98     {
99                 // if slash is right after colon, then we are looking at drive name prefix (C:\) and should
100                 // just skip it, because _stat and _mkdir will both fail for "C:"
101                 if (currpath > mypath && currpath[-1] == ':')
102                         continue;
103         *currpath = '\0';
104         if (_stat(mypath, &fileinfo) != 0)
105         {
106             if (_mkdir(mypath) != 0)
107                                 goto errorexit;
108         }
109         else if (!(fileinfo.st_mode & _S_IFDIR))
110         {
111                         goto errorexit;
112         }
113         *currpath = OSAL_DIR_SEPARATORS[0];
114     }
115
116     // Create full path
117     if  (_mkdir(mypath) != 0)
118         goto errorexit;
119
120 goodexit:
121         free(mypath);
122     return 0;
123 errorexit:
124         free(mypath);
125         return 1;
126 }
127
128 const char * osal_get_shared_filepath(const char *filename, const char *firstsearch, const char *secondsearch)
129 {
130     static char retpath[_MAX_PATH];
131     int i;
132
133     /* if caller gave us any directories to search, then look there first */
134     if (firstsearch != NULL && search_dir_file(retpath, firstsearch, filename) == 0)
135         return retpath;
136     if (secondsearch != NULL && search_dir_file(retpath, secondsearch, filename) == 0)
137         return retpath;
138
139     /* otherwise check our standard paths */
140     if (search_dir_file(retpath, osal_get_user_configpath(), filename) == 0)
141         return retpath;
142     for (i = 0; i < datasearchdirs; i++)
143     {
144         if (search_dir_file(retpath, datasearchpath[i], filename) == 0)
145             return retpath;
146     }
147
148     /* we couldn't find the file */
149     return NULL;
150 }
151
152 const char * osal_get_user_configpath(void)
153 {
154     static char chHomePath[MAX_PATH];
155     LPITEMIDLIST pidl;
156     LPMALLOC pMalloc;
157     struct _stat fileinfo;
158
159     // Get item ID list for the path of user's personal directory
160     HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pidl);
161     // get the path in a char string
162     SHGetPathFromIDList(pidl, chHomePath);
163     // do a bunch of crap just to free some memory
164     hr = SHGetMalloc(&pMalloc);
165     pMalloc->lpVtbl->Free(pMalloc, pidl);
166     pMalloc->lpVtbl->Release(pMalloc);
167
168     // tack on 'mupen64plus'
169     if (chHomePath[strlen(chHomePath)-1] != '\\')
170         strcat(chHomePath, "\\");
171     strcat(chHomePath, "Mupen64Plus");
172
173     // if this directory doesn't exist, then make it
174     if (_stat(chHomePath, &fileinfo) == 0)
175     {
176         strcat(chHomePath, "\\");
177         return chHomePath;
178     }
179     else
180     {
181         osal_mkdirp(chHomePath, 0);
182         if (_stat(chHomePath, &fileinfo) == 0)
183         {
184             strcat(chHomePath, "\\");
185             return chHomePath;
186         }
187     }
188
189     /* otherwise we are in trouble */
190     DebugMessage(M64MSG_ERROR, "Failed to open configuration directory '%s'.", chHomePath);
191     return NULL;
192 }
193
194 const char * osal_get_user_datapath(void)
195 {
196     // in windows, these are all the same
197     return osal_get_user_configpath();
198 }
199
200 const char * osal_get_user_cachepath(void)
201 {
202     // in windows, these are all the same
203     return osal_get_user_configpath();
204 }
205
206