Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

file.cpp 12 KiB

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