std_file.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. #include "precomp_wasabi_bfc.h"
  2. #include "std_file.h"
  3. #include <bfc/file/readdir.h>
  4. #include <bfc/platform/strcmp.h>
  5. #ifdef WIN32
  6. #include <shellapi.h> // for ShellExecute
  7. #endif
  8. #ifdef __APPLE__
  9. #include <unistd.h>
  10. #endif
  11. #define TMPNAME_PREFIX L"WTF"
  12. #ifndef _NOSTUDIO
  13. #include <bfc/parse/pathparse.h>
  14. #undef fopen
  15. #undef fclose
  16. #undef fseek
  17. #undef ftell
  18. #undef fread
  19. #undef fwrite
  20. #undef fgets
  21. #undef fprintf
  22. #undef unlink
  23. #undef access
  24. #ifdef WASABI_COMPILE_FILEREADER
  25. static PtrList<void> fileReaders;
  26. OSFILETYPE FileReaderOpen(const wchar_t *filename, OSFNCSTR mode)
  27. {
  28. OSFILETYPE ret = NULL;
  29. const wchar_t *rFilename = filename;
  30. wchar_t str[WA_MAX_PATH] = L"";
  31. if (wcsstr(filename, L".."))
  32. {
  33. PathParserW pp(filename);
  34. for (int i = 0;i < pp.getNumStrings();i++)
  35. {
  36. if (!wcscmp(pp.enumString(i), L".."))
  37. {
  38. PathParserW pp2(str);
  39. if (pp2.getNumStrings() <= 0)
  40. return NULL;
  41. ASSERTPR(pp2.getNumStrings() > 0, "we don't handle this right, and I'm not sure how to fix it because I'm not sure what the code should do with a leading .. --BU");
  42. int l = (int)wcslen(pp2.enumString(pp2.getNumStrings() - 1));
  43. str[wcslen(str) - l - 1] = 0;
  44. continue;
  45. }
  46. if (!wcscmp(pp.enumString(i), L"."))
  47. continue;
  48. wcscat(str, pp.enumString(i));
  49. wcscat(str, L"/");
  50. }
  51. str[wcslen(str) - 1] = 0;
  52. rFilename = str;
  53. }
  54. if (WASABI_API_FILE && (ret = (OSFILETYPE )WASABI_API_FILE->fileOpen(rFilename, mode)))
  55. {
  56. fileReaders.addItem((void *)ret);
  57. return ret;
  58. }
  59. return 0;
  60. }
  61. #endif
  62. static DWORD mode_to_access(const wchar_t *mode)
  63. {
  64. DWORD access_flags=0;
  65. if (mode)
  66. {
  67. if (mode[0]=='r')
  68. access_flags|=GENERIC_READ;
  69. if (mode[0]=='w' || mode[0] == 'a')
  70. {
  71. access_flags|=GENERIC_WRITE;
  72. if (mode[1] == '+')
  73. access_flags|=GENERIC_READ;
  74. }
  75. }
  76. return access_flags;
  77. }
  78. static DWORD mode_to_create(const wchar_t *mode)
  79. {
  80. if (mode[0]=='r')
  81. return OPEN_EXISTING;
  82. if (mode[0] == 'w')
  83. return CREATE_ALWAYS;
  84. if (mode[0] == 'a')
  85. return OPEN_ALWAYS;
  86. return OPEN_ALWAYS;
  87. }
  88. OSFILETYPE WFOPEN(const wchar_t *filename, OSFNCSTR mode, bool useFileReaders)
  89. {
  90. if (!filename || !*filename)
  91. return OPEN_FAILED;
  92. if (!mode)
  93. mode = WF_WRITE_BINARY;
  94. OSFILETYPE ret = OPEN_FAILED;
  95. if (!WCSNICMP(filename, L"file:", 5))
  96. filename += 5;
  97. #ifdef _WIN32
  98. ret = CreateFileW(filename, mode_to_access(mode), FILE_SHARE_READ, 0, mode_to_create(mode), FILE_FLAG_SEQUENTIAL_SCAN, 0);
  99. if (ret != OPEN_FAILED && mode[0]=='a')
  100. SetFilePointer(ret, 0, 0, FILE_END);
  101. #elif defined(__APPLE__)
  102. // this is kind of slow, but hopefully this function isn't called enough for a major performance impact
  103. // maybe it'd be faster if we did -fshort-wchar and used CFStringCreateWithCharactersNoCopy
  104. CFStringRef cfstr = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)filename, wcslen(filename)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
  105. if (cfstr)
  106. {
  107. size_t len = CFStringGetMaximumSizeOfFileSystemRepresentation(cfstr);
  108. if (len)
  109. {
  110. char *tmpfn = alloca(len);
  111. if (tmpfn)
  112. {
  113. if (CFStringGetFileSystemRepresentation(cfstr, tmpfn, len))
  114. ret = fopen(tmpfn, mode);
  115. }
  116. }
  117. CFRelease(cfstr);
  118. }
  119. #else
  120. #error port me
  121. #endif
  122. if (ret != OPEN_FAILED)
  123. return ret;
  124. // File not found... try to open it with the file readers
  125. // but before that, resolve ".." in path so zip can find it
  126. #ifdef WASABI_COMPILE_FILEREADER
  127. if (useFileReaders)
  128. {
  129. if (ret = FileReaderOpen(filename, mode))
  130. return ret;
  131. else
  132. return OPEN_FAILED;
  133. }
  134. #endif
  135. // File still not found ...
  136. return OPEN_FAILED;
  137. }
  138. int FCLOSE(OSFILETYPE stream)
  139. {
  140. #ifdef WASABI_COMPILE_FILEREADER
  141. if (fileReaders.searchItem((void *)stream) != -1)
  142. {
  143. fileReaders.removeItem((void *)stream);
  144. WASABI_API_FILE->fileClose((void *)stream);
  145. return 0;
  146. }
  147. #endif
  148. return !CloseHandle(stream);
  149. }
  150. static __int64 Seek64(HANDLE hf, __int64 distance, DWORD MoveMethod)
  151. {
  152. LARGE_INTEGER li;
  153. li.QuadPart = distance;
  154. li.LowPart = SetFilePointer (hf, li.LowPart, &li.HighPart, MoveMethod);
  155. if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
  156. {
  157. li.QuadPart = -1;
  158. }
  159. return li.QuadPart;
  160. }
  161. int FSEEK(OSFILETYPE stream, long offset, int origin)
  162. {
  163. #ifdef WASABI_COMPILE_FILEREADER
  164. if (fileReaders.searchItem((void *)stream) != -1)
  165. return WASABI_API_FILE->fileSeek(offset, origin, (void *)stream);
  166. #endif
  167. return (int)Seek64(stream, offset, origin);
  168. }
  169. uint64_t FTELL(OSFILETYPE stream)
  170. {
  171. #ifdef WASABI_COMPILE_FILEREADER
  172. if (fileReaders.searchItem((void *)stream) != -1)
  173. return WASABI_API_FILE->fileTell((void *)stream);
  174. #endif
  175. return Seek64(stream, 0, FILE_CURRENT);
  176. }
  177. size_t FREAD(void *buffer, size_t size, size_t count, OSFILETYPE stream)
  178. {
  179. #ifdef WASABI_COMPILE_FILEREADER
  180. if (fileReaders.searchItem((void *)stream) != -1)
  181. return WASABI_API_FILE->fileRead(buffer, size*count, (void *)stream);
  182. #endif
  183. DWORD bytesRead=0;
  184. ReadFile(stream, buffer, (DWORD)(size*count), &bytesRead, NULL);
  185. return bytesRead;
  186. }
  187. size_t FWRITE(const void *buffer, size_t size, size_t count, OSFILETYPE stream)
  188. {
  189. #ifdef WASABI_COMPILE_FILEREADER
  190. if (fileReaders.searchItem((void *)stream) != -1)
  191. return WASABI_API_FILE->fileWrite(buffer, (int)(size*count), (void *)stream);
  192. #endif
  193. DWORD bytesWritten=0;
  194. WriteFile(stream, buffer, (DWORD)(size*count), &bytesWritten, NULL);
  195. return bytesWritten;
  196. }
  197. uint64_t FGETSIZE(OSFILETYPE stream)
  198. {
  199. #ifdef WASABI_COMPILE_FILEREADER
  200. if (fileReaders.searchItem((void *)stream) != -1)
  201. return WASABI_API_FILE->fileGetFileSize((void *)stream);
  202. #endif
  203. LARGE_INTEGER position;
  204. position.QuadPart=0;
  205. position.LowPart = GetFileSize(stream, (LPDWORD)&position.HighPart);
  206. if (position.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
  207. return INVALID_FILE_SIZE;
  208. else
  209. return position.QuadPart;
  210. }
  211. /*
  212. char *FGETS(char *string, int n, OSFILETYPE stream)
  213. {
  214. #ifdef WASABI_COMPILE_FILEREADER
  215. if (fileReaders.searchItem((void *)stream) != -1)
  216. {
  217. char c;
  218. char *p = string;
  219. for (int i = 0;i < (n - 1);i++)
  220. {
  221. if (!WASABI_API_FILE->fileRead(&c, 1, stream))
  222. {
  223. if (!i) return NULL;
  224. break;
  225. }
  226. if (c == 0x0d) continue;
  227. if (c == 0x0a) break;
  228. *p++ = c;
  229. }
  230. *p = 0;
  231. return string;
  232. }
  233. #endif
  234. return fgets(string, n, stream);
  235. }
  236. */
  237. /*
  238. int FPRINTF(OSFILETYPE stream, const char *format , ...)
  239. {
  240. int ret;
  241. va_list args;
  242. va_start (args, format);
  243. #ifdef WASABI_COMPILE_FILEREADER
  244. if (fileReaders.searchItem((void *)stream) != -1)
  245. {
  246. String p;
  247. ret = p.vsprintf(format, args);
  248. FWRITE(p.v(), p.len(), 1, stream);
  249. }
  250. else
  251. #endif
  252. ret = vfprintf(stream, format, args); //real stdio
  253. va_end (args);
  254. return ret;
  255. }*/
  256. OSFNCSTR TMPNAM2(OSFNSTR str, int val)
  257. {
  258. #ifdef WIN32
  259. wchar_t tempPath[MAX_PATH-14] = {0};
  260. static wchar_t tempName[MAX_PATH];
  261. GetTempPathW(MAX_PATH-14, tempPath);
  262. GetTempFileNameW(tempPath, TMPNAME_PREFIX, val, tempName);
  263. if (str)
  264. {
  265. wcsncpy(str, tempName, MAX_PATH);
  266. return str;
  267. }
  268. else
  269. {
  270. return tempName;
  271. }
  272. #elif defined(LINUX) || defined(__APPLE__)
  273. mkstemp(StringPrintf("%sXXXXXX", str).getNonConstVal());
  274. return (const char *)str;
  275. #endif
  276. }
  277. OSFNCSTR TMPNAM(OSFNSTR string)
  278. {
  279. return TMPNAM2(string, 0);
  280. }
  281. int UNLINK(OSFNCSTR filename)
  282. {
  283. #ifdef WASABI_COMPILE_FILEREADER
  284. return FDELETE(filename);
  285. #elif defined(_WIN32)
  286. return _wunlink(filename);
  287. #else
  288. return unlink(filename); // this has been undefed at the top of this file
  289. #endif
  290. }
  291. int ACCESS(const char *filename, int mode)
  292. {
  293. #ifdef WIN32
  294. return _access(filename, mode);
  295. #else
  296. return access(filename, mode); // this has been undefed at the top of this file
  297. #endif
  298. }
  299. int WACCESS(OSFNCSTR filename, int mode)
  300. {
  301. #ifdef WIN32
  302. return _waccess(filename, mode);
  303. #elif defined(__APPLE__)
  304. return access(filename, mode); // this has been undefed at the top of this file
  305. #endif
  306. }
  307. int FDELETE(const wchar_t *filename, int permanently)
  308. {
  309. #ifdef WASABI_COMPILE_FILEREADER
  310. if (permanently)
  311. return WASABI_API_FILE->fileRemove(filename);
  312. else
  313. return WASABI_API_FILE->fileRemoveUndoable(filename);
  314. #else
  315. return UNLINK(filename);
  316. #endif
  317. }
  318. int MOVEFILE(const wchar_t * filename, const wchar_t *destfilename)
  319. {
  320. #ifdef WASABI_COMPILE_FILEREADER
  321. return WASABI_API_FILE->fileMove(filename, destfilename);
  322. #elif defined(_WIN32)
  323. return MoveFileW(filename, destfilename);
  324. #else
  325. return rename(filename, destfilename);
  326. #endif
  327. }
  328. #ifdef WIN32
  329. #include <shlobj.h>
  330. #include <shellapi.h>
  331. static HRESULT ResolveShortCut(LPCWSTR pszShortcutFile, LPWSTR pszPath, int maxbuf)
  332. {
  333. HRESULT hres;
  334. IShellLinkW* psl;
  335. wchar_t szGotPath[MAX_PATH] = {0};
  336. WIN32_FIND_DATAW wfd;
  337. *pszPath = 0; // assume failure
  338. hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
  339. IID_IShellLinkW, (void **) & psl);
  340. if (SUCCEEDED(hres))
  341. {
  342. IPersistFile* ppf;
  343. hres = psl->QueryInterface(IID_IPersistFile, (void **) & ppf); // OLE 2! Yay! --YO
  344. if (SUCCEEDED(hres))
  345. {
  346. hres = ppf->Load(pszShortcutFile, STGM_READ);
  347. if (SUCCEEDED(hres))
  348. {
  349. hres = psl->Resolve(HWND_DESKTOP, SLR_ANY_MATCH);
  350. if (SUCCEEDED(hres))
  351. {
  352. wcsncpy(szGotPath, pszShortcutFile, MAX_PATH);
  353. hres = psl->GetPath(szGotPath, MAX_PATH, (WIN32_FIND_DATAW *) & wfd,
  354. SLGP_SHORTPATH );
  355. wcsncpy(pszPath, szGotPath, maxbuf);
  356. if (maxbuf) pszPath[maxbuf] = 0;
  357. }
  358. }
  359. ppf->Release();
  360. }
  361. psl->Release();
  362. }
  363. return SUCCEEDED(hres);
  364. }
  365. #endif
  366. // ommitting a maxbuf param was just asking for trouble...
  367. int StdFile::resolveShortcut(OSFNCSTR filename, OSFNSTR destfilename, int maxbuf)
  368. {
  369. #ifdef WIN32
  370. return ResolveShortCut(filename, destfilename, maxbuf);
  371. #elif defined(LINUX) || defined(__APPLE__)
  372. return readlink(filename, destfilename, maxbuf);
  373. #else
  374. #error port me
  375. #endif
  376. }
  377. #endif // ndef _NOSTUDIO