file.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959
  1. /*
  2. * Copyright 2010-2020 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
  4. */
  5. #include "bx_p.h"
  6. #include <bx/file.h>
  7. #ifndef BX_CONFIG_CRT_FILE_READER_WRITER
  8. # define BX_CONFIG_CRT_FILE_READER_WRITER !BX_CRT_NONE
  9. #endif // BX_CONFIG_CRT_FILE_READER_WRITER
  10. #ifndef BX_CONFIG_CRT_DIRECTORY_READER
  11. # define BX_CONFIG_CRT_DIRECTORY_READER (BX_PLATFORM_OS_DESKTOP && !BX_CRT_NONE)
  12. #endif // BX_CONFIG_CRT_DIRECTORY_READER
  13. #if BX_CRT_NONE
  14. # include "crt0.h"
  15. #else
  16. # if BX_CONFIG_CRT_DIRECTORY_READER
  17. # include <dirent.h>
  18. # endif // BX_CONFIG_CRT_DIRECTORY_READER
  19. # include <stdio.h> // remove
  20. # include <sys/stat.h> // stat, mkdir
  21. # if BX_CRT_MSVC
  22. # include <direct.h> // _getcwd
  23. # else
  24. # include <unistd.h> // getcwd
  25. # endif // BX_CRT_MSVC
  26. #endif // !BX_CRT_NONE
  27. namespace bx
  28. {
  29. class NoopWriterImpl : public FileWriterI
  30. {
  31. public:
  32. NoopWriterImpl(void*)
  33. {
  34. }
  35. virtual ~NoopWriterImpl()
  36. {
  37. close();
  38. }
  39. virtual bool open(const FilePath& _filePath, bool _append, Error* _err) override
  40. {
  41. BX_UNUSED(_filePath, _append, _err);
  42. return false;
  43. }
  44. virtual void close() override
  45. {
  46. }
  47. virtual int64_t seek(int64_t _offset, Whence::Enum _whence) override
  48. {
  49. BX_UNUSED(_offset, _whence);
  50. return 0;
  51. }
  52. virtual int32_t write(const void* _data, int32_t _size, Error* _err) override
  53. {
  54. BX_UNUSED(_data, _err);
  55. return _size;
  56. }
  57. };
  58. #if BX_CONFIG_CRT_FILE_READER_WRITER
  59. # if BX_CRT_MSVC
  60. # define fseeko64 _fseeki64
  61. # define ftello64 _ftelli64
  62. # elif 0 \
  63. || BX_PLATFORM_ANDROID \
  64. || BX_PLATFORM_BSD \
  65. || BX_PLATFORM_HAIKU \
  66. || BX_PLATFORM_IOS \
  67. || BX_PLATFORM_OSX
  68. # define fseeko64 fseeko
  69. # define ftello64 ftello
  70. # elif BX_PLATFORM_PS4
  71. # define fseeko64 fseek
  72. # define ftello64 ftell
  73. # endif // BX_
  74. class FileReaderImpl : public FileReaderI
  75. {
  76. public:
  77. FileReaderImpl(FILE* _file)
  78. : m_file(_file)
  79. , m_open(false)
  80. {
  81. }
  82. virtual ~FileReaderImpl()
  83. {
  84. close();
  85. }
  86. virtual bool open(const FilePath& _filePath, Error* _err) override
  87. {
  88. BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
  89. if (NULL != m_file)
  90. {
  91. BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "FileReader: File is already open.");
  92. return false;
  93. }
  94. m_file = fopen(_filePath.getCPtr(), "rb");
  95. if (NULL == m_file)
  96. {
  97. BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "FileReader: Failed to open file.");
  98. return false;
  99. }
  100. m_open = true;
  101. return true;
  102. }
  103. virtual void close() override
  104. {
  105. if (m_open
  106. && NULL != m_file)
  107. {
  108. fclose(m_file);
  109. m_file = NULL;
  110. }
  111. }
  112. virtual int64_t seek(int64_t _offset, Whence::Enum _whence) override
  113. {
  114. BX_ASSERT(NULL != m_file, "Reader/Writer file is not open.");
  115. fseeko64(m_file, _offset, _whence);
  116. return ftello64(m_file);
  117. }
  118. virtual int32_t read(void* _data, int32_t _size, Error* _err) override
  119. {
  120. BX_ASSERT(NULL != m_file, "Reader/Writer file is not open.");
  121. BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
  122. int32_t size = (int32_t)fread(_data, 1, _size, m_file);
  123. if (size != _size)
  124. {
  125. if (0 != feof(m_file) )
  126. {
  127. BX_ERROR_SET(_err, BX_ERROR_READERWRITER_EOF, "FileReader: EOF.");
  128. }
  129. else if (0 != ferror(m_file) )
  130. {
  131. BX_ERROR_SET(_err, BX_ERROR_READERWRITER_READ, "FileReader: read error.");
  132. }
  133. return size >= 0 ? size : 0;
  134. }
  135. return size;
  136. }
  137. private:
  138. FILE* m_file;
  139. bool m_open;
  140. };
  141. class FileWriterImpl : public FileWriterI
  142. {
  143. public:
  144. FileWriterImpl(FILE* _file)
  145. : m_file(_file)
  146. , m_open(false)
  147. {
  148. }
  149. virtual ~FileWriterImpl()
  150. {
  151. close();
  152. }
  153. virtual bool open(const FilePath& _filePath, bool _append, Error* _err) override
  154. {
  155. BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
  156. if (NULL != m_file)
  157. {
  158. BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "FileReader: File is already open.");
  159. return false;
  160. }
  161. m_file = fopen(_filePath.getCPtr(), _append ? "ab" : "wb");
  162. if (NULL == m_file)
  163. {
  164. BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "FileWriter: Failed to open file.");
  165. return false;
  166. }
  167. m_open = true;
  168. return true;
  169. }
  170. virtual void close() override
  171. {
  172. if (m_open
  173. && NULL != m_file)
  174. {
  175. fclose(m_file);
  176. m_file = NULL;
  177. }
  178. }
  179. virtual int64_t seek(int64_t _offset, Whence::Enum _whence) override
  180. {
  181. BX_ASSERT(NULL != m_file, "Reader/Writer file is not open.");
  182. fseeko64(m_file, _offset, _whence);
  183. return ftello64(m_file);
  184. }
  185. virtual int32_t write(const void* _data, int32_t _size, Error* _err) override
  186. {
  187. BX_ASSERT(NULL != m_file, "Reader/Writer file is not open.");
  188. BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
  189. int32_t size = (int32_t)fwrite(_data, 1, _size, m_file);
  190. if (size != _size)
  191. {
  192. BX_ERROR_SET(_err, BX_ERROR_READERWRITER_WRITE, "FileWriter: write failed.");
  193. return size >= 0 ? size : 0;
  194. }
  195. return size;
  196. }
  197. private:
  198. FILE* m_file;
  199. bool m_open;
  200. };
  201. ReaderI* getStdIn()
  202. {
  203. static FileReaderImpl s_stdIn(stdout);
  204. return &s_stdIn;
  205. }
  206. WriterI* getStdOut()
  207. {
  208. static FileWriterImpl s_stdOut(stdout);
  209. return &s_stdOut;
  210. }
  211. WriterI* getStdErr()
  212. {
  213. static FileWriterImpl s_stdOut(stderr);
  214. return &s_stdOut;
  215. }
  216. #elif BX_CRT_NONE
  217. class FileReaderImpl : public FileReaderI
  218. {
  219. public:
  220. FileReaderImpl(void* _file)
  221. : m_fd(int32_t(intptr_t(_file) ) )
  222. , m_open(false)
  223. {
  224. }
  225. virtual ~FileReaderImpl()
  226. {
  227. close();
  228. }
  229. virtual bool open(const FilePath& _filePath, Error* _err) override
  230. {
  231. BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
  232. if (0 != m_fd)
  233. {
  234. BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "FileReader: File is already open.");
  235. return false;
  236. }
  237. m_fd = crt0::open(_filePath.get(), crt0::Open::Read, 0);
  238. if (0 >= m_fd)
  239. {
  240. BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "FileReader: Failed to open file.");
  241. return false;
  242. }
  243. m_open = true;
  244. return true;
  245. }
  246. virtual void close() override
  247. {
  248. if (m_open
  249. && 0 != m_fd)
  250. {
  251. crt0::close(m_fd);
  252. m_fd = 0;
  253. }
  254. }
  255. virtual int64_t seek(int64_t _offset, Whence::Enum _whence) override
  256. {
  257. BX_ASSERT(0 != m_fd, "Reader/Writer file is not open.");
  258. return crt0::seek(m_fd, _offset, crt0::Whence::Enum(_whence) );
  259. }
  260. virtual int32_t read(void* _data, int32_t _size, Error* _err) override
  261. {
  262. BX_ASSERT(0 != m_fd, "Reader/Writer file is not open.");
  263. BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
  264. int32_t size = crt0::read(m_fd, _data, _size);
  265. if (size != _size)
  266. {
  267. BX_UNUSED(_err);
  268. // if (0 != feof(m_file) )
  269. // {
  270. // BX_ERROR_SET(_err, BX_ERROR_READERWRITER_EOF, "FileReader: EOF.");
  271. // }
  272. // else if (0 != ferror(m_file) )
  273. // {
  274. // BX_ERROR_SET(_err, BX_ERROR_READERWRITER_READ, "FileReader: read error.");
  275. // }
  276. return size >= 0 ? size : 0;
  277. }
  278. return size;
  279. }
  280. private:
  281. int32_t m_fd;
  282. bool m_open;
  283. };
  284. class FileWriterImpl : public FileWriterI
  285. {
  286. public:
  287. FileWriterImpl(void* _file)
  288. : m_fd(int32_t(intptr_t(_file) ) )
  289. , m_open(false)
  290. {
  291. }
  292. virtual ~FileWriterImpl()
  293. {
  294. close();
  295. }
  296. virtual bool open(const FilePath& _filePath, bool _append, Error* _err) override
  297. {
  298. BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
  299. if (0 != m_fd)
  300. {
  301. BX_ERROR_SET(_err, BX_ERROR_READERWRITER_ALREADY_OPEN, "FileReader: File is already open.");
  302. return false;
  303. }
  304. m_fd = crt0::open(_filePath.get(), _append ? crt0::Open::Append : crt0::Open::Write, 0600);
  305. if (0 >= m_fd)
  306. {
  307. BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "FileWriter: Failed to open file.");
  308. return false;
  309. }
  310. m_open = true;
  311. return true;
  312. }
  313. virtual void close() override
  314. {
  315. if (m_open
  316. && 0 != m_fd)
  317. {
  318. crt0::close(m_fd);
  319. m_fd = 0;
  320. }
  321. }
  322. virtual int64_t seek(int64_t _offset, Whence::Enum _whence) override
  323. {
  324. BX_ASSERT(0 != m_fd, "Reader/Writer file is not open.");
  325. return crt0::seek(m_fd, _offset, crt0::Whence::Enum(_whence) );
  326. }
  327. virtual int32_t write(const void* _data, int32_t _size, Error* _err) override
  328. {
  329. BX_ASSERT(0 != m_fd, "Reader/Writer file is not open.");
  330. BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
  331. int32_t size = crt0::write(m_fd, _data, _size);
  332. if (size != _size)
  333. {
  334. BX_ERROR_SET(_err, BX_ERROR_READERWRITER_WRITE, "FileWriter: write failed.");
  335. return size >= 0 ? size : 0;
  336. }
  337. return size;
  338. }
  339. private:
  340. int32_t m_fd;
  341. bool m_open;
  342. };
  343. ReaderI* getStdIn()
  344. {
  345. static FileReaderImpl s_stdIn( (void*)intptr_t(crt0::Io::In) );
  346. return &s_stdIn;
  347. }
  348. WriterI* getStdOut()
  349. {
  350. static FileWriterImpl s_stdOut( (void*)intptr_t(crt0::Io::Out) );
  351. return &s_stdOut;
  352. }
  353. WriterI* getStdErr()
  354. {
  355. static FileWriterImpl s_stdOut( (void*)intptr_t(crt0::Io::Err) );
  356. return &s_stdOut;
  357. }
  358. #else
  359. class FileReaderImpl : public FileReaderI
  360. {
  361. public:
  362. FileReaderImpl(void*)
  363. {
  364. }
  365. virtual ~FileReaderImpl()
  366. {
  367. close();
  368. }
  369. virtual bool open(const FilePath& _filePath, Error* _err) override
  370. {
  371. BX_UNUSED(_filePath, _err);
  372. return false;
  373. }
  374. virtual void close() override
  375. {
  376. }
  377. virtual int64_t seek(int64_t _offset, Whence::Enum _whence) override
  378. {
  379. BX_UNUSED(_offset, _whence);
  380. return 0;
  381. }
  382. virtual int32_t read(void* _data, int32_t _size, Error* _err) override
  383. {
  384. BX_UNUSED(_data, _size, _err);
  385. return 0;
  386. }
  387. };
  388. typedef NoopWriterImpl FileWriterImpl;
  389. ReaderI* getStdIn()
  390. {
  391. static FileReaderImpl s_stdIn(NULL);
  392. return &s_stdIn;
  393. }
  394. WriterI* getStdOut()
  395. {
  396. static FileWriterImpl s_stdOut(NULL);
  397. return &s_stdOut;
  398. }
  399. WriterI* getStdErr()
  400. {
  401. static FileWriterImpl s_stdOut(NULL);
  402. return &s_stdOut;
  403. }
  404. #endif // BX_CONFIG_CRT_FILE_READER_WRITER
  405. WriterI* getNullOut()
  406. {
  407. static NoopWriterImpl s_nullOut(NULL);
  408. return &s_nullOut;
  409. }
  410. FileReader::FileReader()
  411. {
  412. BX_STATIC_ASSERT(sizeof(FileReaderImpl) <= sizeof(m_internal) );
  413. BX_PLACEMENT_NEW(m_internal, FileReaderImpl)(NULL);
  414. }
  415. FileReader::~FileReader()
  416. {
  417. FileReaderImpl* impl = reinterpret_cast<FileReaderImpl*>(m_internal);
  418. impl->~FileReaderImpl();
  419. }
  420. bool FileReader::open(const FilePath& _filePath, Error* _err)
  421. {
  422. FileReaderImpl* impl = reinterpret_cast<FileReaderImpl*>(m_internal);
  423. return impl->open(_filePath, _err);
  424. }
  425. void FileReader::close()
  426. {
  427. FileReaderImpl* impl = reinterpret_cast<FileReaderImpl*>(m_internal);
  428. impl->close();
  429. }
  430. int64_t FileReader::seek(int64_t _offset, Whence::Enum _whence)
  431. {
  432. FileReaderImpl* impl = reinterpret_cast<FileReaderImpl*>(m_internal);
  433. return impl->seek(_offset, _whence);
  434. }
  435. int32_t FileReader::read(void* _data, int32_t _size, Error* _err)
  436. {
  437. FileReaderImpl* impl = reinterpret_cast<FileReaderImpl*>(m_internal);
  438. return impl->read(_data, _size, _err);
  439. }
  440. FileWriter::FileWriter()
  441. {
  442. BX_STATIC_ASSERT(sizeof(FileWriterImpl) <= sizeof(m_internal) );
  443. BX_PLACEMENT_NEW(m_internal, FileWriterImpl)(NULL);
  444. }
  445. FileWriter::~FileWriter()
  446. {
  447. FileWriterImpl* impl = reinterpret_cast<FileWriterImpl*>(m_internal);
  448. impl->~FileWriterImpl();
  449. }
  450. bool FileWriter::open(const FilePath& _filePath, bool _append, Error* _err)
  451. {
  452. FileWriterImpl* impl = reinterpret_cast<FileWriterImpl*>(m_internal);
  453. return impl->open(_filePath, _append, _err);
  454. }
  455. void FileWriter::close()
  456. {
  457. FileWriterImpl* impl = reinterpret_cast<FileWriterImpl*>(m_internal);
  458. impl->close();
  459. }
  460. int64_t FileWriter::seek(int64_t _offset, Whence::Enum _whence)
  461. {
  462. FileWriterImpl* impl = reinterpret_cast<FileWriterImpl*>(m_internal);
  463. return impl->seek(_offset, _whence);
  464. }
  465. int32_t FileWriter::write(const void* _data, int32_t _size, Error* _err)
  466. {
  467. FileWriterImpl* impl = reinterpret_cast<FileWriterImpl*>(m_internal);
  468. return impl->write(_data, _size, _err);
  469. }
  470. #if BX_CONFIG_CRT_DIRECTORY_READER
  471. class DirectoryReaderImpl : public ReaderOpenI, public CloserI, public ReaderI
  472. {
  473. public:
  474. DirectoryReaderImpl()
  475. : m_dir(NULL)
  476. , m_pos(0)
  477. {
  478. }
  479. virtual ~DirectoryReaderImpl()
  480. {
  481. close();
  482. }
  483. virtual bool open(const FilePath& _filePath, Error* _err) override
  484. {
  485. BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
  486. m_dir = opendir(_filePath.getCPtr() );
  487. if (NULL == m_dir)
  488. {
  489. BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "DirectoryReader: Failed to open directory.");
  490. return false;
  491. }
  492. m_pos = 0;
  493. return true;
  494. }
  495. virtual void close() override
  496. {
  497. if (NULL != m_dir)
  498. {
  499. closedir(m_dir);
  500. m_dir = NULL;
  501. }
  502. }
  503. virtual int32_t read(void* _data, int32_t _size, Error* _err) override
  504. {
  505. BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
  506. int32_t total = 0;
  507. uint8_t* out = (uint8_t*)_data;
  508. while (0 < _size)
  509. {
  510. if (0 == m_pos)
  511. {
  512. if (!fetch(m_cache, m_dir) )
  513. {
  514. BX_ERROR_SET(_err, BX_ERROR_READERWRITER_EOF, "DirectoryReader: EOF.");
  515. return total;
  516. }
  517. }
  518. const uint8_t* src = (const uint8_t*)&m_cache;
  519. int32_t size = min<int32_t>(_size, sizeof(m_cache)-m_pos);
  520. memCopy(&out[total], &src[m_pos], size);
  521. total += size;
  522. _size -= size;
  523. m_pos += size;
  524. m_pos %= sizeof(m_cache);
  525. }
  526. return total;
  527. }
  528. static bool fetch(FileInfo& _out, DIR* _dir)
  529. {
  530. for (;;)
  531. {
  532. const dirent* item = readdir(_dir);
  533. if (NULL == item)
  534. {
  535. break;
  536. }
  537. if (0 != (item->d_type & DT_DIR) )
  538. {
  539. _out.type = FileType::Dir;
  540. _out.size = UINT64_MAX;
  541. _out.filePath.set(item->d_name);
  542. return true;
  543. }
  544. if (0 != (item->d_type & DT_REG) )
  545. {
  546. _out.type = FileType::File;
  547. _out.size = UINT64_MAX;
  548. _out.filePath.set(item->d_name);
  549. return true;
  550. }
  551. }
  552. return false;
  553. }
  554. FileInfo m_cache;
  555. DIR* m_dir;
  556. int32_t m_pos;
  557. };
  558. #else
  559. class DirectoryReaderImpl : public ReaderOpenI, public CloserI, public ReaderI
  560. {
  561. public:
  562. DirectoryReaderImpl()
  563. {
  564. }
  565. virtual ~DirectoryReaderImpl()
  566. {
  567. }
  568. virtual bool open(const FilePath& _filePath, Error* _err) override
  569. {
  570. BX_UNUSED(_filePath);
  571. BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "DirectoryReader: Failed to open directory.");
  572. return false;
  573. }
  574. virtual void close() override
  575. {
  576. }
  577. virtual int32_t read(void* _data, int32_t _size, Error* _err) override
  578. {
  579. BX_UNUSED(_data, _size);
  580. BX_ASSERT(NULL != _err, "Reader/Writer interface calling functions must handle errors.");
  581. BX_ERROR_SET(_err, BX_ERROR_READERWRITER_EOF, "DirectoryReader: EOF.");
  582. return 0;
  583. }
  584. };
  585. #endif // BX_CONFIG_CRT_DIRECTORY_READER
  586. DirectoryReader::DirectoryReader()
  587. {
  588. BX_STATIC_ASSERT(sizeof(DirectoryReaderImpl) <= sizeof(m_internal) );
  589. BX_PLACEMENT_NEW(m_internal, DirectoryReaderImpl);
  590. }
  591. DirectoryReader::~DirectoryReader()
  592. {
  593. DirectoryReaderImpl* impl = reinterpret_cast<DirectoryReaderImpl*>(m_internal);
  594. impl->~DirectoryReaderImpl();
  595. }
  596. bool DirectoryReader::open(const FilePath& _filePath, Error* _err)
  597. {
  598. DirectoryReaderImpl* impl = reinterpret_cast<DirectoryReaderImpl*>(m_internal);
  599. return impl->open(_filePath, _err);
  600. }
  601. void DirectoryReader::close()
  602. {
  603. DirectoryReaderImpl* impl = reinterpret_cast<DirectoryReaderImpl*>(m_internal);
  604. impl->close();
  605. }
  606. int32_t DirectoryReader::read(void* _data, int32_t _size, Error* _err)
  607. {
  608. DirectoryReaderImpl* impl = reinterpret_cast<DirectoryReaderImpl*>(m_internal);
  609. return impl->read(_data, _size, _err);
  610. }
  611. bool stat(FileInfo& _outFileInfo, const FilePath& _filePath)
  612. {
  613. #if BX_CRT_NONE
  614. BX_UNUSED(_filePath, _outFileInfo);
  615. return false;
  616. #else
  617. _outFileInfo.size = 0;
  618. _outFileInfo.type = FileType::Count;
  619. # if BX_COMPILER_MSVC
  620. struct ::_stat64 st;
  621. int32_t result = ::_stat64(_filePath.getCPtr(), &st);
  622. if (0 != result)
  623. {
  624. return false;
  625. }
  626. if (0 != (st.st_mode & _S_IFREG) )
  627. {
  628. _outFileInfo.type = FileType::File;
  629. }
  630. else if (0 != (st.st_mode & _S_IFDIR) )
  631. {
  632. _outFileInfo.type = FileType::Dir;
  633. }
  634. # else
  635. struct ::stat st;
  636. int32_t result = ::stat(_filePath.getCPtr(), &st);
  637. if (0 != result)
  638. {
  639. return false;
  640. }
  641. if (0 != (st.st_mode & S_IFREG) )
  642. {
  643. _outFileInfo.type = FileType::File;
  644. }
  645. else if (0 != (st.st_mode & S_IFDIR) )
  646. {
  647. _outFileInfo.type = FileType::Dir;
  648. }
  649. # endif // BX_COMPILER_MSVC
  650. _outFileInfo.size = st.st_size;
  651. return true;
  652. #endif // BX_CRT_NONE
  653. }
  654. bool make(const FilePath& _filePath, Error* _err)
  655. {
  656. BX_ERROR_SCOPE(_err);
  657. if (!_err->isOk() )
  658. {
  659. return false;
  660. }
  661. #if BX_CRT_MSVC
  662. int32_t result = ::_mkdir(_filePath.getCPtr() );
  663. #elif BX_CRT_MINGW
  664. int32_t result = ::mkdir(_filePath.getCPtr());
  665. #elif BX_CRT_NONE
  666. BX_UNUSED(_filePath);
  667. int32_t result = -1;
  668. #else
  669. int32_t result = ::mkdir(_filePath.getCPtr(), 0700);
  670. #endif // BX_CRT_MSVC
  671. if (0 != result)
  672. {
  673. BX_ERROR_SET(_err, BX_ERROR_ACCESS, "The parent directory does not allow write permission to the process.");
  674. return false;
  675. }
  676. return true;
  677. }
  678. bool makeAll(const FilePath& _filePath, Error* _err)
  679. {
  680. BX_ERROR_SCOPE(_err);
  681. if (!_err->isOk() )
  682. {
  683. return false;
  684. }
  685. FileInfo fi;
  686. if (stat(fi, _filePath) )
  687. {
  688. if (FileType::Dir == fi.type)
  689. {
  690. return true;
  691. }
  692. BX_ERROR_SET(_err, BX_ERROR_NOT_DIRECTORY, "File already exist, and is not directory.");
  693. return false;
  694. }
  695. const StringView dir = strRTrim(_filePath, "/");
  696. const StringView slash = strRFind(dir, '/');
  697. if (!slash.isEmpty()
  698. && slash.getPtr() - dir.getPtr() > 1)
  699. {
  700. if (!makeAll(StringView(dir.getPtr(), slash.getPtr() ), _err) )
  701. {
  702. return false;
  703. }
  704. }
  705. FilePath path(dir);
  706. return make(path, _err);
  707. }
  708. bool remove(const FilePath& _filePath, Error* _err)
  709. {
  710. BX_ERROR_SCOPE(_err);
  711. if (!_err->isOk() )
  712. {
  713. return false;
  714. }
  715. #if BX_CRT_MSVC
  716. int32_t result = -1;
  717. FileInfo fi;
  718. if (stat(fi, _filePath) )
  719. {
  720. if (FileType::Dir == fi.type)
  721. {
  722. result = ::_rmdir(_filePath.getCPtr() );
  723. }
  724. else
  725. {
  726. result = ::remove(_filePath.getCPtr() );
  727. }
  728. }
  729. #elif BX_CRT_NONE
  730. BX_UNUSED(_filePath);
  731. int32_t result = -1;
  732. #else
  733. int32_t result = ::remove(_filePath.getCPtr() );
  734. #endif // BX_CRT_MSVC
  735. if (0 != result)
  736. {
  737. BX_ERROR_SET(_err, BX_ERROR_ACCESS, "The parent directory does not allow write permission to the process.");
  738. return false;
  739. }
  740. return true;
  741. }
  742. bool removeAll(const FilePath& _filePath, Error* _err)
  743. {
  744. BX_ERROR_SCOPE(_err);
  745. if (remove(_filePath, _err) )
  746. {
  747. return true;
  748. }
  749. _err->reset();
  750. FileInfo fi;
  751. if (!stat(fi, _filePath) )
  752. {
  753. BX_ERROR_SET(_err, BX_ERROR_ACCESS, "The parent directory does not allow write permission to the process.");
  754. return false;
  755. }
  756. if (FileType::Dir != fi.type)
  757. {
  758. BX_ERROR_SET(_err, BX_ERROR_NOT_DIRECTORY, "File already exist, and is not directory.");
  759. return false;
  760. }
  761. Error err;
  762. DirectoryReader dr;
  763. if (!bx::open(&dr, _filePath) )
  764. {
  765. BX_ERROR_SET(_err, BX_ERROR_NOT_DIRECTORY, "File already exist, and is not directory.");
  766. return false;
  767. }
  768. while (err.isOk() )
  769. {
  770. bx::read(&dr, fi, &err);
  771. if (err.isOk() )
  772. {
  773. if (0 == strCmp(fi.filePath, ".")
  774. || 0 == strCmp(fi.filePath, "..") )
  775. {
  776. continue;
  777. }
  778. FilePath path(_filePath);
  779. path.join(fi.filePath);
  780. if (!removeAll(path, _err) )
  781. {
  782. _err->reset();
  783. break;
  784. }
  785. }
  786. }
  787. bx::close(&dr);
  788. return remove(_filePath, _err);
  789. }
  790. } // namespace bx