617 lines
12 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2014 Sam Hocevar <sam@hocevar.net>
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the Do What The Fuck You Want To
  7. // Public License, Version 2, as published by Sam Hocevar. See
  8. // http://www.wtfpl.net/ for more details.
  9. //
  10. #include <lol/engine-internal.h>
  11. #if __ANDROID__
  12. # include <sys/types.h>
  13. # include <android/asset_manager_jni.h>
  14. #endif
  15. #if defined(_WIN32)
  16. # define WIN32_LEAN_AND_MEAN 1
  17. # include <windows.h>
  18. # undef WIN32_LEAN_AND_MEAN
  19. #else
  20. # include <dirent.h>
  21. #endif
  22. #include <atomic>
  23. #include <sys/stat.h>
  24. namespace lol
  25. {
  26. #if __ANDROID__
  27. extern AAssetManager *g_assets;
  28. #endif
  29. //---------------
  30. class FileData
  31. {
  32. friend class File;
  33. FileData()
  34. : m_refcount(0),
  35. m_type(StreamType::File)
  36. { }
  37. void Open(StreamType stream)
  38. {
  39. if (m_type == StreamType::File ||
  40. m_type == StreamType::FileBinary)
  41. return;
  42. m_type = stream;
  43. switch (stream.ToScalar())
  44. {
  45. #if __ANDROID__
  46. /* FIXME: no modes, no error checking, no nothing */
  47. #elif HAVE_STDIO_H
  48. case StreamType::StdIn: m_fd = stdin; break;
  49. case StreamType::StdOut: m_fd = stdout; break;
  50. case StreamType::StdErr: m_fd = stderr; break;
  51. #endif
  52. }
  53. }
  54. void Open(String const &file, FileAccess mode, bool force_binary)
  55. {
  56. m_type = (force_binary) ? (StreamType::FileBinary) : (StreamType::File);
  57. #if __ANDROID__
  58. ASSERT(g_assets);
  59. m_asset = AAssetManager_open(g_assets, file.C(), AASSET_MODE_UNKNOWN);
  60. #elif HAVE_STDIO_H
  61. /* FIXME: no modes, no error checking, no nothing */
  62. stat(file.C(), &m_stat);
  63. String access = (mode == FileAccess::Write) ? ("w") : ("r");
  64. if (force_binary) access += "b";
  65. m_fd = fopen(file.C(), access.C());
  66. #endif
  67. }
  68. inline bool IsValid() const
  69. {
  70. #if __ANDROID__
  71. return !!m_asset;
  72. #elif HAVE_STDIO_H
  73. return !!m_fd;
  74. #else
  75. return false;
  76. #endif
  77. }
  78. void Close()
  79. {
  80. if (m_type != StreamType::File &&
  81. m_type != StreamType::FileBinary)
  82. return;
  83. #if __ANDROID__
  84. if (m_asset)
  85. AAsset_close(m_asset);
  86. m_asset = nullptr;
  87. #elif HAVE_STDIO_H
  88. if (m_fd)
  89. fclose(m_fd);
  90. m_fd = nullptr;
  91. #endif
  92. }
  93. int Read(uint8_t *buf, int count)
  94. {
  95. #if __ANDROID__
  96. return AAsset_read(m_asset, buf, count);
  97. #elif HAVE_STDIO_H
  98. size_t done = fread(buf, 1, count, m_fd);
  99. if (done <= 0)
  100. return -1;
  101. return (int)done;
  102. #else
  103. return 0;
  104. #endif
  105. }
  106. String ReadString()
  107. {
  108. array<uint8_t> buf;
  109. buf.resize(BUFSIZ);
  110. String ret;
  111. while (IsValid())
  112. {
  113. int done = Read(&buf[0], buf.count());
  114. if (done <= 0)
  115. break;
  116. int oldsize = ret.count();
  117. ret.resize(oldsize + done);
  118. memcpy(&ret[oldsize], &buf[0], done);
  119. buf.resize(buf.count() * 3 / 2);
  120. }
  121. return ret;
  122. }
  123. int Write(uint8_t const *buf, int count)
  124. {
  125. #if __ANDROID__
  126. //return AAsset_read(m_asset, buf, count);
  127. return 0;
  128. #elif HAVE_STDIO_H
  129. size_t done = fwrite(buf, 1, count, m_fd);
  130. if (done <= 0)
  131. return -1;
  132. return done;
  133. #else
  134. return 0;
  135. #endif
  136. }
  137. int WriteString(const String &buf)
  138. {
  139. return Write((uint8_t const *)buf.C(), buf.count());
  140. }
  141. long int GetPosFromStart()
  142. {
  143. #if __ANDROID__
  144. return 0;
  145. #elif HAVE_STDIO_H
  146. return ftell(m_fd);
  147. #else
  148. return 0;
  149. #endif
  150. }
  151. void SetPosFromStart(long int pos)
  152. {
  153. #if __ANDROID__
  154. //NOT IMPLEMENTED
  155. #elif HAVE_STDIO_H
  156. fseek(m_fd, pos, SEEK_SET);
  157. #else
  158. //NOT IMPLEMENTED
  159. #endif
  160. }
  161. long int GetSize()
  162. {
  163. #if __ANDROID__
  164. return 0;
  165. #elif HAVE_STDIO_H
  166. return m_stat.st_size;
  167. #else
  168. return 0;
  169. #endif
  170. }
  171. long int GetModificationTime()
  172. {
  173. #if __ANDROID__
  174. return 0;
  175. #elif HAVE_STDIO_H
  176. return (long int)m_stat.st_mtime;
  177. #else
  178. return 0;
  179. #endif
  180. }
  181. //-----------------------
  182. #if __ANDROID__
  183. AAsset *m_asset;
  184. #elif HAVE_STDIO_H
  185. FILE *m_fd;
  186. #endif
  187. std::atomic<int> m_refcount;
  188. StreamType m_type;
  189. struct stat m_stat;
  190. };
  191. //-- FILE --
  192. File::File()
  193. : m_data(new FileData)
  194. {
  195. ++m_data->m_refcount;
  196. }
  197. //--
  198. File::File(File const &that)
  199. : m_data(that.m_data)
  200. {
  201. ++m_data->m_refcount;
  202. }
  203. //--
  204. File &File::operator =(File const &that)
  205. {
  206. if (this == &that)
  207. return *this;
  208. /* FIXME: this needs auditing */
  209. int refcount = --m_data->m_refcount;
  210. if (refcount == 0)
  211. {
  212. m_data->Close();
  213. delete m_data;
  214. }
  215. m_data = that.m_data;
  216. ++m_data->m_refcount;
  217. return *this;
  218. }
  219. //--
  220. File::~File()
  221. {
  222. int refcount = --m_data->m_refcount;
  223. if (refcount == 0)
  224. {
  225. m_data->Close();
  226. delete m_data;
  227. }
  228. }
  229. //--
  230. void File::Open(StreamType stream)
  231. {
  232. m_data->Open(stream);
  233. }
  234. //--
  235. void File::Open(String const &file, FileAccess mode, bool force_binary)
  236. {
  237. m_data->Open(file, mode, force_binary);
  238. }
  239. //--
  240. bool File::IsValid() const
  241. {
  242. return m_data->IsValid();
  243. }
  244. //--
  245. void File::Close()
  246. {
  247. m_data->Close();
  248. }
  249. //--
  250. int File::Read(uint8_t *buf, int count)
  251. {
  252. return m_data->Read(buf, count);
  253. }
  254. //--
  255. String File::ReadString()
  256. {
  257. return m_data->ReadString();
  258. }
  259. //--
  260. int File::Write(uint8_t const *buf, int count)
  261. {
  262. return m_data->Write(buf, count);
  263. }
  264. //--
  265. int File::WriteString(const String &buf)
  266. {
  267. return m_data->WriteString(buf);
  268. }
  269. //--
  270. long int File::GetPosFromStart()
  271. {
  272. return m_data->GetPosFromStart();
  273. }
  274. //--
  275. void File::SetPosFromStart(long int pos)
  276. {
  277. m_data->SetPosFromStart(pos);
  278. }
  279. //--
  280. long int File::GetSize()
  281. {
  282. return m_data->GetSize();
  283. }
  284. //--
  285. long int File::GetModificationTime()
  286. {
  287. return m_data->GetModificationTime();
  288. }
  289. //---------------
  290. class DirectoryData
  291. {
  292. friend class Directory;
  293. DirectoryData() : m_type(StreamType::File)
  294. {
  295. #if __ANDROID__
  296. /* FIXME: not implemented */
  297. #elif defined(_WIN32)
  298. m_handle = INVALID_HANDLE_VALUE;
  299. #elif HAVE_STDIO_H
  300. m_dd = nullptr;
  301. #endif
  302. }
  303. void Open(String const &directory, FileAccess mode)
  304. {
  305. m_type = StreamType::File;
  306. #if __ANDROID__
  307. /* FIXME: not implemented */
  308. #elif defined(_WIN32)
  309. m_directory = directory;
  310. String filter = m_directory + String("*");
  311. filter.replace('/', '\\', true);
  312. WIN32_FIND_DATA FindFileData;
  313. m_handle = FindFirstFile(filter.C(), &FindFileData);
  314. stat(directory.C(), &m_stat);
  315. #elif HAVE_STDIO_H
  316. m_dd = opendir(directory.C());
  317. stat(directory.C(), &m_stat);
  318. #endif
  319. }
  320. void Close()
  321. {
  322. if (m_type != StreamType::File)
  323. return;
  324. if (IsValid())
  325. {
  326. #if __ANDROID__
  327. /* FIXME: not implemented */
  328. #elif defined(_WIN32)
  329. FindClose(m_handle);
  330. #elif HAVE_STDIO_H
  331. closedir(m_dd);
  332. #endif
  333. }
  334. #if __ANDROID__
  335. /* FIXME: not implemented */
  336. #elif defined(_WIN32)
  337. m_handle = INVALID_HANDLE_VALUE;
  338. #elif HAVE_STDIO_H
  339. m_dd = nullptr;
  340. #endif
  341. }
  342. bool GetContentList(array<String>* files, array<String>* directories)
  343. {
  344. if (!IsValid())
  345. return false;
  346. #if __ANDROID__
  347. /* FIXME: not implemented */
  348. #elif defined(_WIN32)
  349. String filter = m_directory + String("*");
  350. filter.replace('/', '\\', true);
  351. WIN32_FIND_DATA find_data;
  352. HANDLE handle = FindFirstFile(filter.C(), &find_data);
  353. bool file_valid = (handle != INVALID_HANDLE_VALUE);
  354. while (file_valid)
  355. {
  356. if (find_data.cFileName[0] != '.')
  357. {
  358. // We have a directory
  359. if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  360. {
  361. if (directories)
  362. *directories << String(std::string(find_data.cFileName).c_str());
  363. }
  364. else
  365. {
  366. if (files)
  367. *files << String(find_data.cFileName);
  368. }
  369. }
  370. //Go for next one
  371. file_valid = !!FindNextFile(m_handle, &find_data);
  372. }
  373. #elif HAVE_STDIO_H
  374. /* FIXME: not implemented */
  375. #endif
  376. return ((files && files->count()) || (directories && directories->count()));
  377. }
  378. inline bool IsValid() const
  379. {
  380. #if __ANDROID__
  381. /* FIXME: not implemented */
  382. #elif defined(_WIN32)
  383. return (m_handle != INVALID_HANDLE_VALUE);
  384. #elif HAVE_STDIO_H
  385. return !!m_dd;
  386. #else
  387. return false;
  388. #endif
  389. }
  390. long int GetModificationTime()
  391. {
  392. #if __ANDROID__
  393. return 0;
  394. #elif HAVE_STDIO_H
  395. return (long int)m_stat.st_mtime;
  396. #else
  397. return 0;
  398. #endif
  399. }
  400. #if __ANDROID__
  401. /* FIXME: not implemented */
  402. #elif defined(_WIN32)
  403. HANDLE m_handle;
  404. String m_directory;
  405. #elif HAVE_STDIO_H
  406. DIR *m_dd;
  407. #endif
  408. std::atomic<int> m_refcount;
  409. StreamType m_type;
  410. struct stat m_stat;
  411. };
  412. //-- DIRECTORY --
  413. Directory::Directory(String const &name)
  414. : m_data(new DirectoryData),
  415. m_name(name + String("/"))
  416. {
  417. ++m_data->m_refcount;
  418. }
  419. //--
  420. Directory::Directory(Directory const &that)
  421. : m_data(that.m_data),
  422. m_name(that.m_name)
  423. {
  424. ++m_data->m_refcount;
  425. }
  426. //--
  427. Directory &Directory::operator =(Directory const &that)
  428. {
  429. if (this == &that)
  430. return *this;
  431. /* FIXME: this needs auditing */
  432. int refcount = --m_data->m_refcount;
  433. if (refcount == 0)
  434. {
  435. m_data->Close();
  436. delete m_data;
  437. }
  438. m_data = that.m_data;
  439. m_name = that.m_name;
  440. ++m_data->m_refcount;
  441. return *this;
  442. }
  443. //--
  444. Directory::~Directory()
  445. {
  446. int refcount = --m_data->m_refcount;
  447. if (refcount == 0)
  448. {
  449. m_data->Close();
  450. delete m_data;
  451. }
  452. }
  453. //--
  454. void Directory::Open(FileAccess mode)
  455. {
  456. return m_data->Open(m_name, mode);
  457. }
  458. //--
  459. bool Directory::IsValid() const
  460. {
  461. return m_data->IsValid();
  462. }
  463. //--
  464. void Directory::Close()
  465. {
  466. m_data->Close();
  467. }
  468. //--
  469. bool Directory::GetContent(array<String>* files, array<Directory>* directories)
  470. {
  471. array<String> sfiles, sdirectories;
  472. bool found_some = m_data->GetContentList(&sfiles, &sdirectories);
  473. if (directories)
  474. for (int i = 0; i < sdirectories.count(); i++)
  475. directories->push(Directory(m_name + sdirectories[i]));
  476. if (files)
  477. for (int i = 0; i < sfiles.count(); i++)
  478. files->push(m_name + sfiles[i]);
  479. return (files && files->count()) || (directories || directories->count());
  480. }
  481. //--
  482. bool Directory::GetContent(array<String>& files, array<Directory>& directories)
  483. {
  484. return GetContent(&files, &directories);
  485. }
  486. //--
  487. bool Directory::GetContent(array<Directory>& directories)
  488. {
  489. return GetContent(nullptr, &directories);
  490. }
  491. //--
  492. bool Directory::GetContent(array<String>& files)
  493. {
  494. return GetContent(&files, nullptr);
  495. }
  496. //--
  497. String Directory::GetName()
  498. {
  499. return m_name;
  500. }
  501. //--
  502. long int Directory::GetModificationTime()
  503. {
  504. return m_data->GetModificationTime();
  505. }
  506. //--
  507. String Directory::GetCurrent()
  508. {
  509. String result;
  510. #if __ANDROID__
  511. /* FIXME: not implemented */
  512. #elif defined(_WIN32)
  513. TCHAR buff[MAX_PATH * 2];
  514. GetCurrentDirectory(MAX_PATH, buff);
  515. result = buff;
  516. result.replace('\\', '/', true);
  517. #elif HAVE_STDIO_H
  518. /* FIXME: not implemented */
  519. #endif
  520. return result;
  521. }
  522. //--
  523. bool Directory::SetCurrent(String directory)
  524. {
  525. #if __ANDROID__
  526. /* FIXME: not implemented */
  527. #elif defined(_WIN32)
  528. String result = directory;
  529. result.replace('/', '\\', true);
  530. return !!SetCurrentDirectory(result.C());
  531. #elif HAVE_STDIO_H
  532. /* FIXME: not implemented */
  533. #endif
  534. return false;
  535. }
  536. } /* namespace lol */