// File: crn_file_utils.cpp // See Copyright Notice and license at the end of inc/crnlib.h #include "crn_core.h" #include "crn_file_utils.h" #include "crn_strutils.h" #if CRNLIB_USE_WIN32_API #include "crn_winhdr.h" #endif #ifdef WIN32 #include #endif #ifdef __GNUC__ #include #include #include #endif namespace crnlib { #if CRNLIB_USE_WIN32_API bool file_utils::is_read_only(const char* pFilename) { uint32 dst_file_attribs = GetFileAttributesA(pFilename); if (dst_file_attribs == INVALID_FILE_ATTRIBUTES) return false; if (dst_file_attribs & FILE_ATTRIBUTE_READONLY) return true; return false; } bool file_utils::disable_read_only(const char* pFilename) { uint32 dst_file_attribs = GetFileAttributesA(pFilename); if (dst_file_attribs == INVALID_FILE_ATTRIBUTES) return false; if (dst_file_attribs & FILE_ATTRIBUTE_READONLY) { dst_file_attribs &= ~FILE_ATTRIBUTE_READONLY; if (SetFileAttributesA(pFilename, dst_file_attribs)) return true; } return false; } bool file_utils::is_older_than(const char* pSrcFilename, const char* pDstFilename) { WIN32_FILE_ATTRIBUTE_DATA src_file_attribs; const BOOL src_file_exists = GetFileAttributesExA(pSrcFilename, GetFileExInfoStandard, &src_file_attribs); WIN32_FILE_ATTRIBUTE_DATA dst_file_attribs; const BOOL dest_file_exists = GetFileAttributesExA(pDstFilename, GetFileExInfoStandard, &dst_file_attribs); if ((dest_file_exists) && (src_file_exists)) { LONG timeComp = CompareFileTime(&src_file_attribs.ftLastWriteTime, &dst_file_attribs.ftLastWriteTime); if (timeComp < 0) return true; } return false; } bool file_utils::does_file_exist(const char* pFilename) { const DWORD fullAttributes = GetFileAttributesA(pFilename); if (fullAttributes == INVALID_FILE_ATTRIBUTES) return false; if (fullAttributes & FILE_ATTRIBUTE_DIRECTORY) return false; return true; } bool file_utils::does_dir_exist(const char* pDir) { //-- Get the file attributes. DWORD fullAttributes = GetFileAttributesA(pDir); if (fullAttributes == INVALID_FILE_ATTRIBUTES) return false; if (fullAttributes & FILE_ATTRIBUTE_DIRECTORY) return true; return false; } bool file_utils::get_file_size(const char* pFilename, uint64& file_size) { file_size = 0; WIN32_FILE_ATTRIBUTE_DATA attr; if (0 == GetFileAttributesExA(pFilename, GetFileExInfoStandard, &attr)) return false; if (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) return false; file_size = static_cast(attr.nFileSizeLow) | (static_cast(attr.nFileSizeHigh) << 32U); return true; } #elif defined( __GNUC__ ) bool file_utils::is_read_only(const char* pFilename) { pFilename; // TODO return false; } bool file_utils::disable_read_only(const char* pFilename) { pFilename; // TODO return false; } bool file_utils::is_older_than(const char *pSrcFilename, const char* pDstFilename) { pSrcFilename, pDstFilename; // TODO return false; } bool file_utils::does_file_exist(const char* pFilename) { struct stat stat_buf; int result = stat(pFilename, &stat_buf); if (result) return false; if (S_ISREG(stat_buf.st_mode)) return true; return false; } bool file_utils::does_dir_exist(const char* pDir) { struct stat stat_buf; int result = stat(pDir, &stat_buf); if (result) return false; if (S_ISDIR(stat_buf.st_mode) || S_ISLNK(stat_buf.st_mode)) return true; return false; } bool file_utils::get_file_size(const char* pFilename, uint64& file_size) { file_size = 0; struct stat stat_buf; int result = stat(pFilename, &stat_buf); if (result) return false; if (!S_ISREG(stat_buf.st_mode)) return false; file_size = stat_buf.st_size; return true; } #else bool file_utils::is_read_only(const char* pFilename) { return false; } bool file_utils::disable_read_only(const char* pFilename) { pFilename; // TODO return false; } bool file_utils::is_older_than(const char *pSrcFilename, const char* pDstFilename) { return false; } bool file_utils::does_file_exist(const char* pFilename) { FILE* pFile; crn_fopen(&pFile, pFilename, "rb"); if (!pFile) return false; fclose(pFile); return true; } bool file_utils::does_dir_exist(const char* pDir) { return false; } bool file_utils::get_file_size(const char* pFilename, uint64& file_size) { FILE* pFile; crn_fopen(&pFile, pFilename, "rb"); if (!pFile) return false; crn_fseek(pFile, 0, SEEK_END); file_size = crn_ftell(pFile); fclose(pFile); return true; } #endif bool file_utils::get_file_size(const char* pFilename, uint32& file_size) { uint64 file_size64; if (!get_file_size(pFilename, file_size64)) { file_size = 0; return false; } if (file_size64 > cUINT32_MAX) file_size64 = cUINT32_MAX; file_size = static_cast(file_size64); return true; } bool file_utils::is_path_separator(char c) { #ifdef WIN32 return (c == '/') || (c == '\\'); #else return (c == '/'); #endif } bool file_utils::is_path_or_drive_separator(char c) { #ifdef WIN32 return (c == '/') || (c == '\\') || (c == ':'); #else return (c == '/'); #endif } bool file_utils::is_drive_separator(char c) { #ifdef WIN32 return (c == ':'); #else c; return false; #endif } bool file_utils::split_path(const char* p, dynamic_string* pDrive, dynamic_string* pDir, dynamic_string* pFilename, dynamic_string* pExt) { CRNLIB_ASSERT(p); #ifdef WIN32 char drive_buf[_MAX_DRIVE]; char dir_buf[_MAX_DIR]; char fname_buf[_MAX_FNAME]; char ext_buf[_MAX_EXT]; #ifdef _MSC_VER // Compiling with MSVC errno_t error = _splitpath_s(p, pDrive ? drive_buf : NULL, pDrive ? _MAX_DRIVE : 0, pDir ? dir_buf : NULL, pDir ? _MAX_DIR : 0, pFilename ? fname_buf : NULL, pFilename ? _MAX_FNAME : 0, pExt ? ext_buf : NULL, pExt ? _MAX_EXT : 0); if (error != 0) return false; #else // Compiling with MinGW _splitpath(p, pDrive ? drive_buf : NULL, pDir ? dir_buf : NULL, pFilename ? fname_buf : NULL, pExt ? ext_buf : NULL); #endif if (pDrive) *pDrive = drive_buf; if (pDir) *pDir = dir_buf; if (pFilename) *pFilename = fname_buf; if (pExt) *pExt = ext_buf; #else char dirtmp[1024]; char nametmp[1024]; strcpy_safe(dirtmp, sizeof(dirtmp), p); strcpy_safe(nametmp, sizeof(nametmp), p); if (pDrive) pDrive->clear(); const char *pDirName = dirname(dirtmp); if (!pDirName) return false; if (pDir) { pDir->set(pDirName); if ((!pDir->is_empty()) && (pDir->back() != '/')) pDir->append_char('/'); } const char *pBaseName = basename(nametmp); if (!pBaseName) return false; if (pFilename) { pFilename->set(pBaseName); remove_extension(*pFilename); } if (pExt) { pExt->set(pBaseName); get_extension(*pExt); *pExt = "." + *pExt; } #endif // #ifdef WIN32 return true; } bool file_utils::split_path(const char* p, dynamic_string& path, dynamic_string& filename) { dynamic_string temp_drive, temp_path, temp_ext; if (!split_path(p, &temp_drive, &temp_path, &filename, &temp_ext)) return false; filename += temp_ext; combine_path(path, temp_drive.get_ptr(), temp_path.get_ptr()); return true; } bool file_utils::get_pathname(const char* p, dynamic_string& path) { dynamic_string temp_drive, temp_path; if (!split_path(p, &temp_drive, &temp_path, NULL, NULL)) return false; combine_path(path, temp_drive.get_ptr(), temp_path.get_ptr()); return true; } bool file_utils::get_filename(const char* p, dynamic_string& filename) { dynamic_string temp_ext; if (!split_path(p, NULL, NULL, &filename, &temp_ext)) return false; filename += temp_ext; return true; } void file_utils::combine_path(dynamic_string& dst, const char* pA, const char* pB) { dynamic_string temp(pA); if ((!temp.is_empty()) && (!is_path_separator(pB[0]))) { char c = temp[temp.get_len() - 1]; if (!is_path_separator(c)) temp.append_char(CRNLIB_PATH_SEPERATOR_CHAR); } temp += pB; dst.swap(temp); } void file_utils::combine_path(dynamic_string& dst, const char* pA, const char* pB, const char* pC) { combine_path(dst, pA, pB); combine_path(dst, dst.get_ptr(), pC); } bool file_utils::full_path(dynamic_string& path) { #ifdef WIN32 char buf[1024]; char* p = _fullpath(buf, path.get_ptr(), sizeof(buf)); if (!p) return false; #else char buf[PATH_MAX]; char* p; dynamic_string pn, fn; split_path(path.get_ptr(), pn, fn); if ((fn == ".") || (fn == "..")) { p = realpath(path.get_ptr(), buf); if (!p) return false; path.set(buf); } else { if (pn.is_empty()) pn = "./"; p = realpath(pn.get_ptr(), buf); if (!p) return false; combine_path(path, buf, fn.get_ptr()); } #endif return true; } bool file_utils::get_extension(dynamic_string& filename) { int sep = -1; #ifdef WIN32 sep = filename.find_right('\\'); #endif if (sep < 0) sep = filename.find_right('/'); int dot = filename.find_right('.'); if (dot < sep) { filename.clear(); return false; } filename.right(dot + 1); return true; } bool file_utils::remove_extension(dynamic_string& filename) { int sep = -1; #ifdef WIN32 sep = filename.find_right('\\'); #endif if (sep < 0) sep = filename.find_right('/'); int dot = filename.find_right('.'); if (dot < sep) return false; filename.left(dot); return true; } bool file_utils::create_path(const dynamic_string& fullpath) { bool got_unc = false; got_unc; dynamic_string cur_path; const int l = fullpath.get_len(); int n = 0; while (n < l) { const char c = fullpath.get_ptr()[n]; const bool sep = is_path_separator(c); const bool back_sep = is_path_separator(cur_path.back()); const bool is_last_char = (n == (l - 1)); if ( ((sep) && (!back_sep)) || (is_last_char) ) { if ((is_last_char) && (!sep)) cur_path.append_char(c); bool valid = !cur_path.is_empty(); #ifdef WIN32 // reject obvious stuff (drives, beginning of UNC paths): // c:\b\cool // \\machine\blah // \cool\blah if ((cur_path.get_len() == 2) && (cur_path[1] == ':')) valid = false; else if ((cur_path.get_len() >= 2) && (cur_path[0] == '\\') && (cur_path[1] == '\\')) { if (!got_unc) valid = false; got_unc = true; } else if (cur_path == "\\") valid = false; #endif if (cur_path == "/") valid = false; if ((valid) && (cur_path.get_len())) { #ifdef WIN32 _mkdir(cur_path.get_ptr()); #else mkdir(cur_path.get_ptr(), S_IRWXU | S_IRWXG | S_IRWXO ); #endif } } cur_path.append_char(c); n++; } return true; } void file_utils::trim_trailing_seperator(dynamic_string& path) { if ((path.get_len()) && (is_path_separator(path.back()))) path.truncate(path.get_len() - 1); } // See http://www.codeproject.com/KB/string/wildcmp.aspx int file_utils::wildcmp(const char* pWild, const char* pString) { const char* cp = NULL, *mp = NULL; while ((*pString) && (*pWild != '*')) { if ((*pWild != *pString) && (*pWild != '?')) return 0; pWild++; pString++; } // Either *pString=='\0' or *pWild='*' here. while (*pString) { if (*pWild == '*') { if (!*++pWild) return 1; mp = pWild; cp = pString+1; } else if ((*pWild == *pString) || (*pWild == '?')) { pWild++; pString++; } else { pWild = mp; pString = cp++; } } while (*pWild == '*') pWild++; return !*pWild; } bool file_utils::write_buf_to_file(const char* pPath, const void* pData, size_t data_size) { FILE *pFile = NULL; #ifdef _MSC_VER // Compiling with MSVC if (fopen_s(&pFile, pPath, "wb")) return false; #else pFile = fopen(pPath, "wb"); #endif if (!pFile) return false; bool success = fwrite(pData, 1, data_size, pFile) == data_size; fclose(pFile); return success; } } // namespace crnlib