FileSystem.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. #include "Base.h"
  2. #include "FileSystem.h"
  3. #include "Properties.h"
  4. #include "Stream.h"
  5. #include "Platform.h"
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #ifdef WIN32
  9. #include <windows.h>
  10. #include <tchar.h>
  11. #include <stdio.h>
  12. #include <direct.h>
  13. #define gp_stat _stat
  14. #define gp_stat_struct struct stat
  15. #else
  16. #define __EXT_POSIX2
  17. #include <libgen.h>
  18. #include <dirent.h>
  19. #define gp_stat stat
  20. #define gp_stat_struct struct stat
  21. #endif
  22. #ifdef __ANDROID__
  23. #include <android/asset_manager.h>
  24. extern AAssetManager* __assetManager;
  25. #endif
  26. namespace gameplay
  27. {
  28. #ifdef __ANDROID__
  29. #include <unistd.h>
  30. static void makepath(std::string path, int mode)
  31. {
  32. std::vector<std::string> dirs;
  33. while (path.length() > 0)
  34. {
  35. int index = path.find('/');
  36. std::string dir = (index == -1 ) ? path : path.substr(0, index);
  37. if (dir.length() > 0)
  38. dirs.push_back(dir);
  39. if (index + 1 >= path.length() || index == -1)
  40. break;
  41. path = path.substr(index + 1);
  42. }
  43. struct stat s;
  44. std::string dirPath;
  45. for (unsigned int i = 0; i < dirs.size(); i++)
  46. {
  47. dirPath += "/";
  48. dirPath += dirs[i];
  49. if (stat(dirPath.c_str(), &s) != 0)
  50. {
  51. // Directory does not exist.
  52. if (mkdir(dirPath.c_str(), 0777) != 0)
  53. {
  54. GP_ERROR("Failed to create directory: '%s'", dirPath.c_str());
  55. return;
  56. }
  57. }
  58. }
  59. return;
  60. }
  61. /**
  62. * Returns true if the file exists in the android read-only asset directory.
  63. */
  64. static bool androidFileExists(const char* filePath)
  65. {
  66. AAsset* asset = AAssetManager_open(__assetManager, filePath, AASSET_MODE_RANDOM);
  67. if (asset)
  68. {
  69. int lenght = AAsset_getLength(asset);
  70. AAsset_close(asset);
  71. return length > 0;
  72. }
  73. return false;
  74. }
  75. #endif
  76. /** @script{ignore} */
  77. static std::string __resourcePath("./");
  78. static std::string __assetPath("");
  79. static std::map<std::string, std::string> __aliases;
  80. /**
  81. * Gets the fully resolved path.
  82. * If the path is relative then it will be prefixed with the resource path.
  83. * Aliases will be converted to a relative path.
  84. *
  85. * @param path The path to resolve.
  86. * @param fullPath The full resolved path. (out param)
  87. */
  88. static void getFullPath(const char* path, std::string& fullPath)
  89. {
  90. if (FileSystem::isAbsolutePath(path))
  91. {
  92. fullPath.assign(path);
  93. }
  94. else
  95. {
  96. fullPath.assign(__resourcePath);
  97. fullPath += FileSystem::resolvePath(path);
  98. }
  99. }
  100. /**
  101. *
  102. * @script{ignore}
  103. */
  104. class FileStream : public Stream
  105. {
  106. public:
  107. friend class FileSystem;
  108. ~FileStream();
  109. virtual bool canRead();
  110. virtual bool canWrite();
  111. virtual bool canSeek();
  112. virtual void close();
  113. virtual size_t read(void* ptr, size_t size, size_t count);
  114. virtual char* readLine(char* str, int num);
  115. virtual size_t write(const void* ptr, size_t size, size_t count);
  116. virtual bool eof();
  117. virtual size_t length();
  118. virtual long int position();
  119. virtual bool seek(long int offset, int origin);
  120. virtual bool rewind();
  121. static FileStream* create(const char* filePath, const char* mode);
  122. private:
  123. FileStream(FILE* file);
  124. private:
  125. FILE* _file;
  126. bool _canRead;
  127. bool _canWrite;
  128. };
  129. #ifdef __ANDROID__
  130. /**
  131. *
  132. * @script{ignore}
  133. */
  134. class FileStreamAndroid : public Stream
  135. {
  136. public:
  137. friend class FileSystem;
  138. ~FileStreamAndroid();
  139. virtual bool canRead();
  140. virtual bool canWrite();
  141. virtual bool canSeek();
  142. virtual void close();
  143. virtual size_t read(void* ptr, size_t size, size_t count);
  144. virtual char* readLine(char* str, int num);
  145. virtual size_t write(const void* ptr, size_t size, size_t count);
  146. virtual bool eof();
  147. virtual size_t length();
  148. virtual long int position();
  149. virtual bool seek(long int offset, int origin);
  150. virtual bool rewind();
  151. static FileStreamAndroid* create(const char* filePath, const char* mode);
  152. private:
  153. FileStreamAndroid(AAsset* asset);
  154. private:
  155. AAsset* _asset;
  156. };
  157. #endif
  158. /////////////////////////////
  159. FileSystem::FileSystem()
  160. {
  161. }
  162. FileSystem::~FileSystem()
  163. {
  164. }
  165. void FileSystem::setResourcePath(const char* path)
  166. {
  167. __resourcePath = path == NULL ? "" : path;
  168. }
  169. const char* FileSystem::getResourcePath()
  170. {
  171. return __resourcePath.c_str();
  172. }
  173. void FileSystem::loadResourceAliases(const char* aliasFilePath)
  174. {
  175. Properties* properties = Properties::create(aliasFilePath);
  176. if (properties)
  177. {
  178. Properties* aliases;
  179. while ((aliases = properties->getNextNamespace()) != NULL)
  180. {
  181. loadResourceAliases(aliases);
  182. }
  183. }
  184. SAFE_DELETE(properties);
  185. }
  186. void FileSystem::loadResourceAliases(Properties* properties)
  187. {
  188. assert(properties);
  189. const char* name;
  190. while ((name = properties->getNextProperty()) != NULL)
  191. {
  192. __aliases[name] = properties->getString();
  193. }
  194. }
  195. std::string FileSystem::displayFileDialog(size_t dialogMode, const char* title, const char* filterDescription, const char* filterExtensions, const char* initialDirectory)
  196. {
  197. return Platform::displayFileDialog(dialogMode, title, filterDescription, filterExtensions, initialDirectory);
  198. }
  199. const char* FileSystem::resolvePath(const char* path)
  200. {
  201. GP_ASSERT(path);
  202. size_t len = strlen(path);
  203. if (len > 1 && path[0] == '@')
  204. {
  205. std::string alias(path + 1);
  206. std::map<std::string, std::string>::const_iterator itr = __aliases.find(alias);
  207. if (itr == __aliases.end())
  208. return path; // no matching alias found
  209. return itr->second.c_str();
  210. }
  211. return path;
  212. }
  213. bool FileSystem::listFiles(const char* dirPath, std::vector<std::string>& files)
  214. {
  215. #ifdef WIN32
  216. std::string path(FileSystem::getResourcePath());
  217. if (dirPath && strlen(dirPath) > 0)
  218. {
  219. path.append(dirPath);
  220. }
  221. path.append("/*");
  222. // Convert char to wchar
  223. std::basic_string<TCHAR> wPath;
  224. wPath.assign(path.begin(), path.end());
  225. WIN32_FIND_DATA FindFileData;
  226. HANDLE hFind = FindFirstFile(wPath.c_str(), &FindFileData);
  227. if (hFind == INVALID_HANDLE_VALUE)
  228. {
  229. return false;
  230. }
  231. do
  232. {
  233. // Add to the list if this is not a directory
  234. if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  235. {
  236. // Convert wchar to char
  237. std::basic_string<TCHAR> wfilename(FindFileData.cFileName);
  238. std::string filename;
  239. filename.assign(wfilename.begin(), wfilename.end());
  240. files.push_back(filename);
  241. }
  242. } while (FindNextFile(hFind, &FindFileData) != 0);
  243. FindClose(hFind);
  244. return true;
  245. #else
  246. std::string path(FileSystem::getResourcePath());
  247. if (dirPath && strlen(dirPath) > 0)
  248. {
  249. path.append(dirPath);
  250. }
  251. path.append("/.");
  252. bool result = false;
  253. struct dirent* dp;
  254. DIR* dir = opendir(path.c_str());
  255. if (dir != NULL)
  256. {
  257. while ((dp = readdir(dir)) != NULL)
  258. {
  259. std::string filepath(path);
  260. filepath.append("/");
  261. filepath.append(dp->d_name);
  262. struct stat buf;
  263. if (!stat(filepath.c_str(), &buf))
  264. {
  265. // Add to the list if this is not a directory
  266. if (!S_ISDIR(buf.st_mode))
  267. {
  268. files.push_back(dp->d_name);
  269. }
  270. }
  271. }
  272. closedir(dir);
  273. result = true;
  274. }
  275. #ifdef __ANDROID__
  276. // List the files that are in the android APK at this path
  277. AAssetDir* assetDir = AAssetManager_openDir(__assetManager, dirPath);
  278. if (assetDir != NULL)
  279. {
  280. AAssetDir_rewind(assetDir);
  281. const char* file = NULL;
  282. while ((file = AAssetDir_getNextFileName(assetDir)) != NULL)
  283. {
  284. std::string filename(file);
  285. // Check if this file was already added to the list because it was copied to the SD card.
  286. if (find(files.begin(), files.end(), filename) == files.end())
  287. {
  288. files.push_back(filename);
  289. }
  290. }
  291. AAssetDir_close(assetDir);
  292. result = true;
  293. }
  294. #endif
  295. return result;
  296. #endif
  297. }
  298. bool FileSystem::fileExists(const char* filePath)
  299. {
  300. GP_ASSERT(filePath);
  301. std::string fullPath;
  302. #ifdef __ANDROID__
  303. fullPath = __assetPath;
  304. fullPath += resolvePath(filePath);
  305. if (androidFileExists(fullPath.c_str()))
  306. {
  307. return true;
  308. }
  309. #endif
  310. getFullPath(filePath, fullPath);
  311. gp_stat_struct s;
  312. return stat(fullPath.c_str(), &s) == 0;
  313. }
  314. Stream* FileSystem::open(const char* path, size_t streamMode)
  315. {
  316. char modeStr[] = "rb";
  317. if ((streamMode & WRITE) != 0)
  318. modeStr[0] = 'w';
  319. #ifdef __ANDROID__
  320. std::string fullPath(__resourcePath);
  321. fullPath += resolvePath(path);
  322. if ((streamMode & WRITE) != 0)
  323. {
  324. // Open a file on the SD card
  325. size_t index = fullPath.rfind('/');
  326. if (index != std::string::npos)
  327. {
  328. std::string directoryPath = fullPath.substr(0, index);
  329. gp_stat_struct s;
  330. if (stat(directoryPath.c_str(), &s) != 0)
  331. makepath(directoryPath, 0777);
  332. }
  333. return FileStream::create(fullPath.c_str(), modeStr);
  334. }
  335. else
  336. {
  337. // First try the SD card
  338. Stream* stream = FileStream::create(fullPath.c_str(), modeStr);
  339. if (!stream)
  340. {
  341. // Otherwise fall-back to assets loaded via the AssetManager
  342. fullPath = __assetPath;
  343. fullPath += resolvePath(path);
  344. stream = FileStreamAndroid::create(fullPath.c_str(), modeStr);
  345. }
  346. return stream;
  347. }
  348. #else
  349. std::string fullPath;
  350. getFullPath(path, fullPath);
  351. FileStream* stream = FileStream::create(fullPath.c_str(), modeStr);
  352. return stream;
  353. #endif
  354. }
  355. FILE* FileSystem::openFile(const char* filePath, const char* mode)
  356. {
  357. GP_ASSERT(filePath);
  358. GP_ASSERT(mode);
  359. std::string fullPath;
  360. getFullPath(filePath, fullPath);
  361. createFileFromAsset(filePath);
  362. FILE* fp = fopen(fullPath.c_str(), mode);
  363. return fp;
  364. }
  365. char* FileSystem::readAll(const char* filePath, int* fileSize)
  366. {
  367. GP_ASSERT(filePath);
  368. // Open file for reading.
  369. std::unique_ptr<Stream> stream(open(filePath));
  370. if (stream.get() == NULL)
  371. {
  372. GP_ERROR("Failed to load file: %s", filePath);
  373. return NULL;
  374. }
  375. size_t size = stream->length();
  376. // Read entire file contents.
  377. char* buffer = new char[size + 1];
  378. size_t read = stream->read(buffer, 1, size);
  379. if (read != size)
  380. {
  381. GP_ERROR("Failed to read complete contents of file '%s' (amount read vs. file size: %u < %u).", filePath, read, size);
  382. SAFE_DELETE_ARRAY(buffer);
  383. return NULL;
  384. }
  385. // Force the character buffer to be NULL-terminated.
  386. buffer[size] = '\0';
  387. if (fileSize)
  388. {
  389. *fileSize = (int)size;
  390. }
  391. return buffer;
  392. }
  393. bool FileSystem::isAbsolutePath(const char* filePath)
  394. {
  395. if (filePath == 0 || filePath[0] == '\0')
  396. return false;
  397. #ifdef WIN32
  398. if (filePath[1] != '\0')
  399. {
  400. char first = filePath[0];
  401. return (filePath[1] == ':' && ((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z')));
  402. }
  403. return false;
  404. #else
  405. return filePath[0] == '/';
  406. #endif
  407. }
  408. void FileSystem::setAssetPath(const char* path)
  409. {
  410. __assetPath = path;
  411. }
  412. const char* FileSystem::getAssetPath()
  413. {
  414. return __assetPath.c_str();
  415. }
  416. void FileSystem::createFileFromAsset(const char* path)
  417. {
  418. #ifdef __ANDROID__
  419. static std::set<std::string> upToDateAssets;
  420. GP_ASSERT(path);
  421. std::string fullPath(__resourcePath);
  422. std::string resolvedPath = FileSystem::resolvePath(path);
  423. fullPath += resolvedPath;
  424. std::string directoryPath = fullPath.substr(0, fullPath.rfind('/'));
  425. struct stat s;
  426. if (stat(directoryPath.c_str(), &s) != 0)
  427. makepath(directoryPath, 0777);
  428. // To ensure that the files on the file system corresponding to the assets in the APK bundle
  429. // are always up to date (and in sync), we copy them from the APK to the file system once
  430. // for each time the process (game) runs.
  431. if (upToDateAssets.find(fullPath) == upToDateAssets.end())
  432. {
  433. AAsset* asset = AAssetManager_open(__assetManager, resolvedPath.c_str(), AASSET_MODE_RANDOM);
  434. if (asset)
  435. {
  436. const void* data = AAsset_getBuffer(asset);
  437. int length = AAsset_getLength(asset);
  438. FILE* file = fopen(fullPath.c_str(), "wb");
  439. if (file != NULL)
  440. {
  441. int ret = fwrite(data, sizeof(unsigned char), length, file);
  442. if (fclose(file) != 0)
  443. {
  444. GP_ERROR("Failed to close file on file system created from APK asset '%s'.", path);
  445. return;
  446. }
  447. if (ret != length)
  448. {
  449. GP_ERROR("Failed to write all data from APK asset '%s' to file on file system.", path);
  450. return;
  451. }
  452. }
  453. else
  454. {
  455. GP_ERROR("Failed to create file on file system from APK asset '%s'.", path);
  456. return;
  457. }
  458. upToDateAssets.insert(fullPath);
  459. }
  460. }
  461. #endif
  462. }
  463. std::string FileSystem::getDirectoryName(const char* path)
  464. {
  465. if (path == NULL || strlen(path) == 0)
  466. {
  467. return "";
  468. }
  469. #ifdef WIN32
  470. char drive[_MAX_DRIVE];
  471. char dir[_MAX_DIR];
  472. _splitpath(path, drive, dir, NULL, NULL);
  473. std::string dirname;
  474. size_t driveLength = strlen(drive);
  475. if (driveLength > 0)
  476. {
  477. dirname.reserve(driveLength + strlen(dir));
  478. dirname.append(drive);
  479. dirname.append(dir);
  480. }
  481. else
  482. {
  483. dirname.assign(dir);
  484. }
  485. std::replace(dirname.begin(), dirname.end(), '\\', '/');
  486. return dirname;
  487. #else
  488. // dirname() modifies the input string so create a temp string
  489. std::string dirname;
  490. char* tempPath = new char[strlen(path) + 1];
  491. strcpy(tempPath, path);
  492. char* dir = ::dirname(tempPath);
  493. if (dir && strlen(dir) > 0)
  494. {
  495. dirname.assign(dir);
  496. // dirname() strips off the trailing '/' so add it back to be consistent with Windows
  497. dirname.append("/");
  498. }
  499. SAFE_DELETE_ARRAY(tempPath);
  500. return dirname;
  501. #endif
  502. }
  503. std::string FileSystem::getExtension(const char* path)
  504. {
  505. const char* str = strrchr(path, '.');
  506. if (str == NULL)
  507. return "";
  508. std::string ext;
  509. size_t len = strlen(str);
  510. for (size_t i = 0; i < len; ++i)
  511. ext += std::toupper(str[i]);
  512. return ext;
  513. }
  514. //////////////////
  515. FileStream::FileStream(FILE* file)
  516. : _file(file), _canRead(false), _canWrite(false)
  517. {
  518. }
  519. FileStream::~FileStream()
  520. {
  521. if (_file)
  522. {
  523. close();
  524. }
  525. }
  526. FileStream* FileStream::create(const char* filePath, const char* mode)
  527. {
  528. FILE* file = fopen(filePath, mode);
  529. if (file)
  530. {
  531. FileStream* stream = new FileStream(file);
  532. const char* s = mode;
  533. while (s != NULL && *s != '\0')
  534. {
  535. if (*s == 'r')
  536. stream->_canRead = true;
  537. else if (*s == 'w')
  538. stream->_canWrite = true;
  539. ++s;
  540. }
  541. return stream;
  542. }
  543. return NULL;
  544. }
  545. bool FileStream::canRead()
  546. {
  547. return _file && _canRead;
  548. }
  549. bool FileStream::canWrite()
  550. {
  551. return _file && _canWrite;
  552. }
  553. bool FileStream::canSeek()
  554. {
  555. return _file != NULL;
  556. }
  557. void FileStream::close()
  558. {
  559. if (_file)
  560. fclose(_file);
  561. _file = NULL;
  562. }
  563. size_t FileStream::read(void* ptr, size_t size, size_t count)
  564. {
  565. if (!_file)
  566. return 0;
  567. return fread(ptr, size, count, _file);
  568. }
  569. char* FileStream::readLine(char* str, int num)
  570. {
  571. if (!_file)
  572. return 0;
  573. return fgets(str, num, _file);
  574. }
  575. size_t FileStream::write(const void* ptr, size_t size, size_t count)
  576. {
  577. if (!_file)
  578. return 0;
  579. return fwrite(ptr, size, count, _file);
  580. }
  581. bool FileStream::eof()
  582. {
  583. if (!_file || feof(_file))
  584. return true;
  585. return ((size_t)position()) >= length();
  586. }
  587. size_t FileStream::length()
  588. {
  589. size_t len = 0;
  590. if (canSeek())
  591. {
  592. long int pos = position();
  593. if (seek(0, SEEK_END))
  594. {
  595. len = position();
  596. }
  597. seek(pos, SEEK_SET);
  598. }
  599. return len;
  600. }
  601. long int FileStream::position()
  602. {
  603. if (!_file)
  604. return -1;
  605. return ftell(_file);
  606. }
  607. bool FileStream::seek(long int offset, int origin)
  608. {
  609. if (!_file)
  610. return false;
  611. return fseek(_file, offset, origin) == 0;
  612. }
  613. bool FileStream::rewind()
  614. {
  615. if (canSeek())
  616. {
  617. ::rewind(_file);
  618. return true;
  619. }
  620. return false;
  621. }
  622. ////////////////////////////////
  623. #ifdef __ANDROID__
  624. FileStreamAndroid::FileStreamAndroid(AAsset* asset)
  625. : _asset(asset)
  626. {
  627. }
  628. FileStreamAndroid::~FileStreamAndroid()
  629. {
  630. if (_asset)
  631. close();
  632. }
  633. FileStreamAndroid* FileStreamAndroid::create(const char* filePath, const char* mode)
  634. {
  635. AAsset* asset = AAssetManager_open(__assetManager, filePath, AASSET_MODE_RANDOM);
  636. if (asset)
  637. {
  638. FileStreamAndroid* stream = new FileStreamAndroid(asset);
  639. return stream;
  640. }
  641. return NULL;
  642. }
  643. bool FileStreamAndroid::canRead()
  644. {
  645. return true;
  646. }
  647. bool FileStreamAndroid::canWrite()
  648. {
  649. return false;
  650. }
  651. bool FileStreamAndroid::canSeek()
  652. {
  653. return true;
  654. }
  655. void FileStreamAndroid::close()
  656. {
  657. if (_asset)
  658. AAsset_close(_asset);
  659. _asset = NULL;
  660. }
  661. size_t FileStreamAndroid::read(void* ptr, size_t size, size_t count)
  662. {
  663. int result = AAsset_read(_asset, ptr, size * count);
  664. return result > 0 ? ((size_t)result) / size : 0;
  665. }
  666. char* FileStreamAndroid::readLine(char* str, int num)
  667. {
  668. if (num <= 0)
  669. return NULL;
  670. char c = 0;
  671. size_t maxCharsToRead = num - 1;
  672. for (size_t i = 0; i < maxCharsToRead; ++i)
  673. {
  674. size_t result = read(&c, 1, 1);
  675. if (result != 1)
  676. {
  677. str[i] = '\0';
  678. break;
  679. }
  680. if (c == '\n')
  681. {
  682. str[i] = c;
  683. str[i + 1] = '\0';
  684. break;
  685. }
  686. else if(c == '\r')
  687. {
  688. str[i] = c;
  689. // next may be '\n'
  690. size_t pos = position();
  691. char nextChar = 0;
  692. if (read(&nextChar, 1, 1) != 1)
  693. {
  694. // no more characters
  695. str[i + 1] = '\0';
  696. break;
  697. }
  698. if (nextChar == '\n')
  699. {
  700. if (i == maxCharsToRead - 1)
  701. {
  702. str[i + 1] = '\0';
  703. break;
  704. }
  705. else
  706. {
  707. str[i + 1] = nextChar;
  708. str[i + 2] = '\0';
  709. break;
  710. }
  711. }
  712. else
  713. {
  714. seek(pos, SEEK_SET);
  715. str[i + 1] = '\0';
  716. break;
  717. }
  718. }
  719. str[i] = c;
  720. }
  721. return str; // what if first read failed?
  722. }
  723. size_t FileStreamAndroid::write(const void* ptr, size_t size, size_t count)
  724. {
  725. return 0;
  726. }
  727. bool FileStreamAndroid::eof()
  728. {
  729. return position() >= length();
  730. }
  731. size_t FileStreamAndroid::length()
  732. {
  733. return (size_t)AAsset_getLength(_asset);
  734. }
  735. long int FileStreamAndroid::position()
  736. {
  737. return AAsset_getLength(_asset) - AAsset_getRemainingLength(_asset);
  738. }
  739. bool FileStreamAndroid::seek(long int offset, int origin)
  740. {
  741. return AAsset_seek(_asset, offset, origin) != -1;
  742. }
  743. bool FileStreamAndroid::rewind()
  744. {
  745. if (canSeek())
  746. {
  747. return AAsset_seek(_asset, 0, SEEK_SET) != -1;
  748. }
  749. return false;
  750. }
  751. #endif
  752. }