crn_file_utils.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. // File: crn_file_utils.cpp
  2. // See Copyright Notice and license at the end of inc/crnlib.h
  3. #include "crn_core.h"
  4. #include "crn_file_utils.h"
  5. #include "crn_strutils.h"
  6. #if CRNLIB_USE_WIN32_API
  7. #include "crn_winhdr.h"
  8. #endif
  9. #ifdef WIN32
  10. #include <direct.h>
  11. #endif
  12. #ifdef __GNUC__
  13. #include <sys/stat.h>
  14. #include <sys/stat.h>
  15. #include <libgen.h>
  16. #endif
  17. namespace crnlib
  18. {
  19. #if CRNLIB_USE_WIN32_API
  20. bool file_utils::is_read_only(const char* pFilename)
  21. {
  22. uint32 dst_file_attribs = GetFileAttributesA(pFilename);
  23. if (dst_file_attribs == INVALID_FILE_ATTRIBUTES)
  24. return false;
  25. if (dst_file_attribs & FILE_ATTRIBUTE_READONLY)
  26. return true;
  27. return false;
  28. }
  29. bool file_utils::disable_read_only(const char* pFilename)
  30. {
  31. uint32 dst_file_attribs = GetFileAttributesA(pFilename);
  32. if (dst_file_attribs == INVALID_FILE_ATTRIBUTES)
  33. return false;
  34. if (dst_file_attribs & FILE_ATTRIBUTE_READONLY)
  35. {
  36. dst_file_attribs &= ~FILE_ATTRIBUTE_READONLY;
  37. if (SetFileAttributesA(pFilename, dst_file_attribs))
  38. return true;
  39. }
  40. return false;
  41. }
  42. bool file_utils::is_older_than(const char* pSrcFilename, const char* pDstFilename)
  43. {
  44. WIN32_FILE_ATTRIBUTE_DATA src_file_attribs;
  45. const BOOL src_file_exists = GetFileAttributesExA(pSrcFilename, GetFileExInfoStandard, &src_file_attribs);
  46. WIN32_FILE_ATTRIBUTE_DATA dst_file_attribs;
  47. const BOOL dest_file_exists = GetFileAttributesExA(pDstFilename, GetFileExInfoStandard, &dst_file_attribs);
  48. if ((dest_file_exists) && (src_file_exists))
  49. {
  50. LONG timeComp = CompareFileTime(&src_file_attribs.ftLastWriteTime, &dst_file_attribs.ftLastWriteTime);
  51. if (timeComp < 0)
  52. return true;
  53. }
  54. return false;
  55. }
  56. bool file_utils::does_file_exist(const char* pFilename)
  57. {
  58. const DWORD fullAttributes = GetFileAttributesA(pFilename);
  59. if (fullAttributes == INVALID_FILE_ATTRIBUTES)
  60. return false;
  61. if (fullAttributes & FILE_ATTRIBUTE_DIRECTORY)
  62. return false;
  63. return true;
  64. }
  65. bool file_utils::does_dir_exist(const char* pDir)
  66. {
  67. //-- Get the file attributes.
  68. DWORD fullAttributes = GetFileAttributesA(pDir);
  69. if (fullAttributes == INVALID_FILE_ATTRIBUTES)
  70. return false;
  71. if (fullAttributes & FILE_ATTRIBUTE_DIRECTORY)
  72. return true;
  73. return false;
  74. }
  75. bool file_utils::get_file_size(const char* pFilename, uint64& file_size)
  76. {
  77. file_size = 0;
  78. WIN32_FILE_ATTRIBUTE_DATA attr;
  79. if (0 == GetFileAttributesExA(pFilename, GetFileExInfoStandard, &attr))
  80. return false;
  81. if (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  82. return false;
  83. file_size = static_cast<uint64>(attr.nFileSizeLow) | (static_cast<uint64>(attr.nFileSizeHigh) << 32U);
  84. return true;
  85. }
  86. #elif defined( __GNUC__ )
  87. bool file_utils::is_read_only(const char* pFilename)
  88. {
  89. pFilename;
  90. // TODO
  91. return false;
  92. }
  93. bool file_utils::disable_read_only(const char* pFilename)
  94. {
  95. pFilename;
  96. // TODO
  97. return false;
  98. }
  99. bool file_utils::is_older_than(const char *pSrcFilename, const char* pDstFilename)
  100. {
  101. pSrcFilename, pDstFilename;
  102. // TODO
  103. return false;
  104. }
  105. bool file_utils::does_file_exist(const char* pFilename)
  106. {
  107. struct stat stat_buf;
  108. int result = stat(pFilename, &stat_buf);
  109. if (result)
  110. return false;
  111. if (S_ISREG(stat_buf.st_mode))
  112. return true;
  113. return false;
  114. }
  115. bool file_utils::does_dir_exist(const char* pDir)
  116. {
  117. struct stat stat_buf;
  118. int result = stat(pDir, &stat_buf);
  119. if (result)
  120. return false;
  121. if (S_ISDIR(stat_buf.st_mode) || S_ISLNK(stat_buf.st_mode))
  122. return true;
  123. return false;
  124. }
  125. bool file_utils::get_file_size(const char* pFilename, uint64& file_size)
  126. {
  127. file_size = 0;
  128. struct stat stat_buf;
  129. int result = stat(pFilename, &stat_buf);
  130. if (result)
  131. return false;
  132. if (!S_ISREG(stat_buf.st_mode))
  133. return false;
  134. file_size = stat_buf.st_size;
  135. return true;
  136. }
  137. #else
  138. bool file_utils::is_read_only(const char* pFilename)
  139. {
  140. return false;
  141. }
  142. bool file_utils::disable_read_only(const char* pFilename)
  143. {
  144. pFilename;
  145. // TODO
  146. return false;
  147. }
  148. bool file_utils::is_older_than(const char *pSrcFilename, const char* pDstFilename)
  149. {
  150. return false;
  151. }
  152. bool file_utils::does_file_exist(const char* pFilename)
  153. {
  154. FILE* pFile;
  155. crn_fopen(&pFile, pFilename, "rb");
  156. if (!pFile)
  157. return false;
  158. fclose(pFile);
  159. return true;
  160. }
  161. bool file_utils::does_dir_exist(const char* pDir)
  162. {
  163. return false;
  164. }
  165. bool file_utils::get_file_size(const char* pFilename, uint64& file_size)
  166. {
  167. FILE* pFile;
  168. crn_fopen(&pFile, pFilename, "rb");
  169. if (!pFile)
  170. return false;
  171. crn_fseek(pFile, 0, SEEK_END);
  172. file_size = crn_ftell(pFile);
  173. fclose(pFile);
  174. return true;
  175. }
  176. #endif
  177. bool file_utils::get_file_size(const char* pFilename, uint32& file_size)
  178. {
  179. uint64 file_size64;
  180. if (!get_file_size(pFilename, file_size64))
  181. {
  182. file_size = 0;
  183. return false;
  184. }
  185. if (file_size64 > cUINT32_MAX)
  186. file_size64 = cUINT32_MAX;
  187. file_size = static_cast<uint32>(file_size64);
  188. return true;
  189. }
  190. bool file_utils::is_path_separator(char c)
  191. {
  192. #ifdef WIN32
  193. return (c == '/') || (c == '\\');
  194. #else
  195. return (c == '/');
  196. #endif
  197. }
  198. bool file_utils::is_path_or_drive_separator(char c)
  199. {
  200. #ifdef WIN32
  201. return (c == '/') || (c == '\\') || (c == ':');
  202. #else
  203. return (c == '/');
  204. #endif
  205. }
  206. bool file_utils::is_drive_separator(char c)
  207. {
  208. #ifdef WIN32
  209. return (c == ':');
  210. #else
  211. c;
  212. return false;
  213. #endif
  214. }
  215. bool file_utils::split_path(const char* p, dynamic_string* pDrive, dynamic_string* pDir, dynamic_string* pFilename, dynamic_string* pExt)
  216. {
  217. CRNLIB_ASSERT(p);
  218. #ifdef WIN32
  219. char drive_buf[_MAX_DRIVE];
  220. char dir_buf[_MAX_DIR];
  221. char fname_buf[_MAX_FNAME];
  222. char ext_buf[_MAX_EXT];
  223. #ifdef _MSC_VER
  224. // Compiling with MSVC
  225. errno_t error = _splitpath_s(p,
  226. pDrive ? drive_buf : NULL, pDrive ? _MAX_DRIVE : 0,
  227. pDir ? dir_buf : NULL, pDir ? _MAX_DIR : 0,
  228. pFilename ? fname_buf : NULL, pFilename ? _MAX_FNAME : 0,
  229. pExt ? ext_buf : NULL, pExt ? _MAX_EXT : 0);
  230. if (error != 0)
  231. return false;
  232. #else
  233. // Compiling with MinGW
  234. _splitpath(p,
  235. pDrive ? drive_buf : NULL,
  236. pDir ? dir_buf : NULL,
  237. pFilename ? fname_buf : NULL,
  238. pExt ? ext_buf : NULL);
  239. #endif
  240. if (pDrive) *pDrive = drive_buf;
  241. if (pDir) *pDir = dir_buf;
  242. if (pFilename) *pFilename = fname_buf;
  243. if (pExt) *pExt = ext_buf;
  244. #else
  245. char dirtmp[1024];
  246. char nametmp[1024];
  247. strcpy_safe(dirtmp, sizeof(dirtmp), p);
  248. strcpy_safe(nametmp, sizeof(nametmp), p);
  249. if (pDrive) pDrive->clear();
  250. const char *pDirName = dirname(dirtmp);
  251. if (!pDirName)
  252. return false;
  253. if (pDir)
  254. {
  255. pDir->set(pDirName);
  256. if ((!pDir->is_empty()) && (pDir->back() != '/'))
  257. pDir->append_char('/');
  258. }
  259. const char *pBaseName = basename(nametmp);
  260. if (!pBaseName)
  261. return false;
  262. if (pFilename)
  263. {
  264. pFilename->set(pBaseName);
  265. remove_extension(*pFilename);
  266. }
  267. if (pExt)
  268. {
  269. pExt->set(pBaseName);
  270. get_extension(*pExt);
  271. *pExt = "." + *pExt;
  272. }
  273. #endif // #ifdef WIN32
  274. return true;
  275. }
  276. bool file_utils::split_path(const char* p, dynamic_string& path, dynamic_string& filename)
  277. {
  278. dynamic_string temp_drive, temp_path, temp_ext;
  279. if (!split_path(p, &temp_drive, &temp_path, &filename, &temp_ext))
  280. return false;
  281. filename += temp_ext;
  282. combine_path(path, temp_drive.get_ptr(), temp_path.get_ptr());
  283. return true;
  284. }
  285. bool file_utils::get_pathname(const char* p, dynamic_string& path)
  286. {
  287. dynamic_string temp_drive, temp_path;
  288. if (!split_path(p, &temp_drive, &temp_path, NULL, NULL))
  289. return false;
  290. combine_path(path, temp_drive.get_ptr(), temp_path.get_ptr());
  291. return true;
  292. }
  293. bool file_utils::get_filename(const char* p, dynamic_string& filename)
  294. {
  295. dynamic_string temp_ext;
  296. if (!split_path(p, NULL, NULL, &filename, &temp_ext))
  297. return false;
  298. filename += temp_ext;
  299. return true;
  300. }
  301. void file_utils::combine_path(dynamic_string& dst, const char* pA, const char* pB)
  302. {
  303. dynamic_string temp(pA);
  304. if ((!temp.is_empty()) && (!is_path_separator(pB[0])))
  305. {
  306. char c = temp[temp.get_len() - 1];
  307. if (!is_path_separator(c))
  308. temp.append_char(CRNLIB_PATH_SEPERATOR_CHAR);
  309. }
  310. temp += pB;
  311. dst.swap(temp);
  312. }
  313. void file_utils::combine_path(dynamic_string& dst, const char* pA, const char* pB, const char* pC)
  314. {
  315. combine_path(dst, pA, pB);
  316. combine_path(dst, dst.get_ptr(), pC);
  317. }
  318. bool file_utils::full_path(dynamic_string& path)
  319. {
  320. #ifdef WIN32
  321. char buf[1024];
  322. char* p = _fullpath(buf, path.get_ptr(), sizeof(buf));
  323. if (!p)
  324. return false;
  325. #else
  326. char buf[PATH_MAX];
  327. char* p;
  328. dynamic_string pn, fn;
  329. split_path(path.get_ptr(), pn, fn);
  330. if ((fn == ".") || (fn == ".."))
  331. {
  332. p = realpath(path.get_ptr(), buf);
  333. if (!p)
  334. return false;
  335. path.set(buf);
  336. }
  337. else
  338. {
  339. if (pn.is_empty())
  340. pn = "./";
  341. p = realpath(pn.get_ptr(), buf);
  342. if (!p)
  343. return false;
  344. combine_path(path, buf, fn.get_ptr());
  345. }
  346. #endif
  347. return true;
  348. }
  349. bool file_utils::get_extension(dynamic_string& filename)
  350. {
  351. int sep = -1;
  352. #ifdef WIN32
  353. sep = filename.find_right('\\');
  354. #endif
  355. if (sep < 0)
  356. sep = filename.find_right('/');
  357. int dot = filename.find_right('.');
  358. if (dot < sep)
  359. {
  360. filename.clear();
  361. return false;
  362. }
  363. filename.right(dot + 1);
  364. return true;
  365. }
  366. bool file_utils::remove_extension(dynamic_string& filename)
  367. {
  368. int sep = -1;
  369. #ifdef WIN32
  370. sep = filename.find_right('\\');
  371. #endif
  372. if (sep < 0)
  373. sep = filename.find_right('/');
  374. int dot = filename.find_right('.');
  375. if (dot < sep)
  376. return false;
  377. filename.left(dot);
  378. return true;
  379. }
  380. bool file_utils::create_path(const dynamic_string& fullpath)
  381. {
  382. bool got_unc = false; got_unc;
  383. dynamic_string cur_path;
  384. const int l = fullpath.get_len();
  385. int n = 0;
  386. while (n < l)
  387. {
  388. const char c = fullpath.get_ptr()[n];
  389. const bool sep = is_path_separator(c);
  390. const bool back_sep = is_path_separator(cur_path.back());
  391. const bool is_last_char = (n == (l - 1));
  392. if ( ((sep) && (!back_sep)) || (is_last_char) )
  393. {
  394. if ((is_last_char) && (!sep))
  395. cur_path.append_char(c);
  396. bool valid = !cur_path.is_empty();
  397. #ifdef WIN32
  398. // reject obvious stuff (drives, beginning of UNC paths):
  399. // c:\b\cool
  400. // \\machine\blah
  401. // \cool\blah
  402. if ((cur_path.get_len() == 2) && (cur_path[1] == ':'))
  403. valid = false;
  404. else if ((cur_path.get_len() >= 2) && (cur_path[0] == '\\') && (cur_path[1] == '\\'))
  405. {
  406. if (!got_unc)
  407. valid = false;
  408. got_unc = true;
  409. }
  410. else if (cur_path == "\\")
  411. valid = false;
  412. #endif
  413. if (cur_path == "/")
  414. valid = false;
  415. if ((valid) && (cur_path.get_len()))
  416. {
  417. #ifdef WIN32
  418. _mkdir(cur_path.get_ptr());
  419. #else
  420. mkdir(cur_path.get_ptr(), S_IRWXU | S_IRWXG | S_IRWXO );
  421. #endif
  422. }
  423. }
  424. cur_path.append_char(c);
  425. n++;
  426. }
  427. return true;
  428. }
  429. void file_utils::trim_trailing_seperator(dynamic_string& path)
  430. {
  431. if ((path.get_len()) && (is_path_separator(path.back())))
  432. path.truncate(path.get_len() - 1);
  433. }
  434. // See http://www.codeproject.com/KB/string/wildcmp.aspx
  435. int file_utils::wildcmp(const char* pWild, const char* pString)
  436. {
  437. const char* cp = NULL, *mp = NULL;
  438. while ((*pString) && (*pWild != '*'))
  439. {
  440. if ((*pWild != *pString) && (*pWild != '?'))
  441. return 0;
  442. pWild++;
  443. pString++;
  444. }
  445. // Either *pString=='\0' or *pWild='*' here.
  446. while (*pString)
  447. {
  448. if (*pWild == '*')
  449. {
  450. if (!*++pWild)
  451. return 1;
  452. mp = pWild;
  453. cp = pString+1;
  454. }
  455. else if ((*pWild == *pString) || (*pWild == '?'))
  456. {
  457. pWild++;
  458. pString++;
  459. }
  460. else
  461. {
  462. pWild = mp;
  463. pString = cp++;
  464. }
  465. }
  466. while (*pWild == '*')
  467. pWild++;
  468. return !*pWild;
  469. }
  470. bool file_utils::write_buf_to_file(const char* pPath, const void* pData, size_t data_size)
  471. {
  472. FILE *pFile = NULL;
  473. #ifdef _MSC_VER
  474. // Compiling with MSVC
  475. if (fopen_s(&pFile, pPath, "wb"))
  476. return false;
  477. #else
  478. pFile = fopen(pPath, "wb");
  479. #endif
  480. if (!pFile)
  481. return false;
  482. bool success = fwrite(pData, 1, data_size, pFile) == data_size;
  483. fclose(pFile);
  484. return success;
  485. }
  486. } // namespace crnlib