Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

10 лет назад
11 лет назад
11 лет назад
11 лет назад
10 лет назад
11 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
11 лет назад
10 лет назад
11 лет назад
11 лет назад
11 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
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 */