/* * * Copyright (c) 1998-2002 * John Maddock * * Use, modification and distribution are subject to the * Boost Software License, Version 1.0. (See accompanying file * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) * */ /* * LOCATION: see http://www.boost.org for most recent version. * FILE: fileiter.cpp * VERSION: see * DESCRIPTION: Implements file io primitives + directory searching for class cutl_details_boost::RegEx. */ #define BOOST_REGEX_SOURCE #include #include #include #include #include #include #include #include #include #if defined(BOOST_NO_STDC_NAMESPACE) namespace std{ using ::sprintf; using ::fseek; using ::fread; using ::ftell; using ::fopen; using ::fclose; using ::FILE; using ::strcpy; using ::strcpy; using ::strcat; using ::strcmp; using ::strlen; } #endif #ifndef BOOST_REGEX_NO_FILEITER #if defined(__CYGWIN__) || defined(__CYGWIN32__) #include #endif #ifdef BOOST_MSVC # pragma warning(disable: 4800) #endif namespace cutl_details_boost{ namespace re_detail{ // start with the operating system specific stuff: #if (defined(__BORLANDC__) || defined(BOOST_REGEX_FI_WIN32_DIR) || defined(BOOST_MSVC)) && !defined(BOOST_RE_NO_WIN32) // platform is DOS or Windows // directories are separated with '\\' // and names are insensitive of case BOOST_REGEX_DECL const char* _fi_sep = "\\"; const char* _fi_sep_alt = "/"; #define BOOST_REGEX_FI_TRANSLATE(c) std::tolower(c) #else // platform is not DOS or Windows // directories are separated with '/' // and names are sensitive of case BOOST_REGEX_DECL const char* _fi_sep = "/"; const char* _fi_sep_alt = _fi_sep; #define BOOST_REGEX_FI_TRANSLATE(c) c #endif #ifdef BOOST_REGEX_FI_WIN32_MAP void mapfile::open(const char* file) { #if defined(BOOST_NO_ANSI_APIS) int filename_size = strlen(file); LPWSTR wide_file = (LPWSTR)_alloca( (filename_size + 1) * sizeof(WCHAR) ); if(::MultiByteToWideChar(CP_ACP, 0, file, filename_size, wide_file, filename_size + 1) == 0) hfile = INVALID_HANDLE_VALUE; else hfile = CreateFileW(wide_file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); #elif defined(__CYGWIN__)||defined(__CYGWIN32__) char win32file[ MAX_PATH ]; cygwin_conv_to_win32_path( file, win32file ); hfile = CreateFileA(win32file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); #else hfile = CreateFileA(file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); #endif if(hfile != INVALID_HANDLE_VALUE) { hmap = CreateFileMapping(hfile, 0, PAGE_READONLY, 0, 0, 0); if((hmap == INVALID_HANDLE_VALUE) || (hmap == NULL)) { CloseHandle(hfile); hmap = 0; hfile = 0; std::runtime_error err("Unable to create file mapping."); cutl_details_boost::re_detail::raise_runtime_error(err); } _first = static_cast(MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 0)); if(_first == 0) { CloseHandle(hmap); CloseHandle(hfile); hmap = 0; hfile = 0; std::runtime_error err("Unable to create file mapping."); } _last = _first + GetFileSize(hfile, 0); } else { hfile = 0; #ifndef BOOST_NO_EXCEPTIONS throw std::runtime_error("Unable to open file."); #else BOOST_REGEX_NOEH_ASSERT(hfile != INVALID_HANDLE_VALUE); #endif } } void mapfile::close() { if(hfile != INVALID_HANDLE_VALUE) { UnmapViewOfFile((void*)_first); CloseHandle(hmap); CloseHandle(hfile); hmap = hfile = 0; _first = _last = 0; } } #elif !defined(BOOST_RE_NO_STL) mapfile_iterator& mapfile_iterator::operator = (const mapfile_iterator& i) { if(file && node) file->unlock(node); file = i.file; node = i.node; offset = i.offset; if(file) file->lock(node); return *this; } mapfile_iterator& mapfile_iterator::operator++ () { if((++offset == mapfile::buf_size) && file) { ++node; offset = 0; file->lock(node); file->unlock(node-1); } return *this; } mapfile_iterator mapfile_iterator::operator++ (int) { mapfile_iterator temp(*this); if((++offset == mapfile::buf_size) && file) { ++node; offset = 0; file->lock(node); file->unlock(node-1); } return temp; } mapfile_iterator& mapfile_iterator::operator-- () { if((offset == 0) && file) { --node; offset = mapfile::buf_size - 1; file->lock(node); file->unlock(node + 1); } else --offset; return *this; } mapfile_iterator mapfile_iterator::operator-- (int) { mapfile_iterator temp(*this); if((offset == 0) && file) { --node; offset = mapfile::buf_size - 1; file->lock(node); file->unlock(node + 1); } else --offset; return temp; } mapfile_iterator operator + (const mapfile_iterator& i, long off) { mapfile_iterator temp(i); temp += off; return temp; } mapfile_iterator operator - (const mapfile_iterator& i, long off) { mapfile_iterator temp(i); temp -= off; return temp; } mapfile::iterator mapfile::begin()const { return mapfile_iterator(this, 0); } mapfile::iterator mapfile::end()const { return mapfile_iterator(this, _size); } void mapfile::lock(pointer* node)const { BOOST_ASSERT(node >= _first); BOOST_ASSERT(node <= _last); if(node < _last) { if(*node == 0) { if(condemed.empty()) { *node = new char[sizeof(int) + buf_size]; *(reinterpret_cast(*node)) = 1; } else { pointer* p = condemed.front(); condemed.pop_front(); *node = *p; *p = 0; *(reinterpret_cast(*node)) = 1; } std::size_t read_size = 0; int read_pos = std::fseek(hfile, (node - _first) * buf_size, SEEK_SET); if(0 == read_pos && node == _last - 1) read_size = std::fread(*node + sizeof(int), _size % buf_size, 1, hfile); else read_size = std::fread(*node + sizeof(int), buf_size, 1, hfile); #ifndef BOOST_NO_EXCEPTIONS if((read_size == 0) || (std::ferror(hfile))) { throw std::runtime_error("Unable to read file."); } #else BOOST_REGEX_NOEH_ASSERT((0 == std::ferror(hfile)) && (read_size != 0)); #endif } else { if(*reinterpret_cast(*node) == 0) { *reinterpret_cast(*node) = 1; condemed.remove(node); } else ++(*reinterpret_cast(*node)); } } } void mapfile::unlock(pointer* node)const { BOOST_ASSERT(node >= _first); BOOST_ASSERT(node <= _last); if(node < _last) { if(--(*reinterpret_cast(*node)) == 0) { condemed.push_back(node); } } } long int get_file_length(std::FILE* hfile) { long int result; std::fseek(hfile, 0, SEEK_END); result = std::ftell(hfile); std::fseek(hfile, 0, SEEK_SET); return result; } void mapfile::open(const char* file) { hfile = std::fopen(file, "rb"); #ifndef BOOST_NO_EXCEPTIONS try{ #endif if(hfile != 0) { _size = get_file_length(hfile); long cnodes = (_size + buf_size - 1) / buf_size; // check that number of nodes is not too high: if(cnodes > (long)((INT_MAX) / sizeof(pointer*))) { std::fclose(hfile); hfile = 0; _size = 0; return; } _first = new pointer[(int)cnodes]; _last = _first + cnodes; std::memset(_first, 0, cnodes*sizeof(pointer)); } else { std::runtime_error err("Unable to open file."); } #ifndef BOOST_NO_EXCEPTIONS }catch(...) { close(); throw; } #endif } void mapfile::close() { if(hfile != 0) { pointer* p = _first; while(p != _last) { if(*p) delete[] *p; ++p; } delete[] _first; _size = 0; _first = _last = 0; std::fclose(hfile); hfile = 0; condemed.erase(condemed.begin(), condemed.end()); } } #endif inline _fi_find_handle find_first_file(const char* wild, _fi_find_data& data) { #ifdef BOOST_NO_ANSI_APIS std::size_t wild_size = std::strlen(wild); LPWSTR wide_wild = (LPWSTR)_alloca( (wild_size + 1) * sizeof(WCHAR) ); if (::MultiByteToWideChar(CP_ACP, 0, wild, wild_size, wide_wild, wild_size + 1) == 0) return _fi_invalid_handle; return FindFirstFileW(wide_wild, &data); #else return FindFirstFileA(wild, &data); #endif } inline bool find_next_file(_fi_find_handle hf, _fi_find_data& data) { #ifdef BOOST_NO_ANSI_APIS return FindNextFileW(hf, &data); #else return FindNextFileA(hf, &data); #endif } inline void copy_find_file_result_with_overflow_check(const _fi_find_data& data, char* path, size_t max_size) { #ifdef BOOST_NO_ANSI_APIS if (::WideCharToMultiByte(CP_ACP, 0, data.cFileName, -1, path, max_size, NULL, NULL) == 0) re_detail::overflow_error_if_not_zero(1); #else re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(path, max_size, data.cFileName)); #endif } inline bool is_not_current_or_parent_path_string(const _fi_find_data& data) { #ifdef BOOST_NO_ANSI_APIS return (std::wcscmp(data.cFileName, L".") && std::wcscmp(data.cFileName, L"..")); #else return (std::strcmp(data.cFileName, ".") && std::strcmp(data.cFileName, "..")); #endif } file_iterator::file_iterator() { _root = _path = 0; ref = 0; #ifndef BOOST_NO_EXCEPTIONS try{ #endif _root = new char[MAX_PATH]; BOOST_REGEX_NOEH_ASSERT(_root) _path = new char[MAX_PATH]; BOOST_REGEX_NOEH_ASSERT(_path) ptr = _path; *_path = 0; *_root = 0; ref = new file_iterator_ref(); BOOST_REGEX_NOEH_ASSERT(ref) ref->hf = _fi_invalid_handle; ref->count = 1; #ifndef BOOST_NO_EXCEPTIONS } catch(...) { delete[] _root; delete[] _path; delete ref; throw; } #endif } file_iterator::file_iterator(const char* wild) { _root = _path = 0; ref = 0; #ifndef BOOST_NO_EXCEPTIONS try{ #endif _root = new char[MAX_PATH]; BOOST_REGEX_NOEH_ASSERT(_root) _path = new char[MAX_PATH]; BOOST_REGEX_NOEH_ASSERT(_path) re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, wild)); ptr = _root; while(*ptr)++ptr; while((ptr > _root) && (*ptr != *_fi_sep) && (*ptr != *_fi_sep_alt))--ptr; if((ptr == _root) && ( (*ptr== *_fi_sep) || (*ptr==*_fi_sep_alt) ) ) { _root[1]='\0'; re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, _root)); } else { *ptr = 0; re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, _root)); if(*_path == 0) re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, ".")); re_detail::overflow_error_if_not_zero(re_detail::strcat_s(_path, MAX_PATH, _fi_sep)); } ptr = _path + std::strlen(_path); ref = new file_iterator_ref(); BOOST_REGEX_NOEH_ASSERT(ref) ref->hf = find_first_file(wild, ref->_data); ref->count = 1; if(ref->hf == _fi_invalid_handle) { *_path = 0; ptr = _path; } else { copy_find_file_result_with_overflow_check(ref->_data, ptr, (MAX_PATH - (ptr - _path))); if(ref->_data.dwFileAttributes & _fi_dir) next(); } #ifndef BOOST_NO_EXCEPTIONS } catch(...) { delete[] _root; delete[] _path; delete ref; throw; } #endif } file_iterator::file_iterator(const file_iterator& other) { _root = _path = 0; ref = 0; #ifndef BOOST_NO_EXCEPTIONS try{ #endif _root = new char[MAX_PATH]; BOOST_REGEX_NOEH_ASSERT(_root) _path = new char[MAX_PATH]; BOOST_REGEX_NOEH_ASSERT(_path) re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, other._root)); re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, other._path)); ptr = _path + (other.ptr - other._path); ref = other.ref; #ifndef BOOST_NO_EXCEPTIONS } catch(...) { delete[] _root; delete[] _path; throw; } #endif ++(ref->count); } file_iterator& file_iterator::operator=(const file_iterator& other) { re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, other._root)); re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, other._path)); ptr = _path + (other.ptr - other._path); if(--(ref->count) == 0) { if(ref->hf != _fi_invalid_handle) FindClose(ref->hf); delete ref; } ref = other.ref; ++(ref->count); return *this; } file_iterator::~file_iterator() { delete[] _root; delete[] _path; if(--(ref->count) == 0) { if(ref->hf != _fi_invalid_handle) FindClose(ref->hf); delete ref; } } file_iterator file_iterator::operator++(int) { file_iterator temp(*this); next(); return temp; } void file_iterator::next() { if(ref->hf != _fi_invalid_handle) { bool cont = true; while(cont) { cont = find_next_file(ref->hf, ref->_data); if(cont && ((ref->_data.dwFileAttributes & _fi_dir) == 0)) break; } if(!cont) { // end of sequence FindClose(ref->hf); ref->hf = _fi_invalid_handle; *_path = 0; ptr = _path; } else copy_find_file_result_with_overflow_check(ref->_data, ptr, MAX_PATH - (ptr - _path)); } } directory_iterator::directory_iterator() { _root = _path = 0; ref = 0; #ifndef BOOST_NO_EXCEPTIONS try{ #endif _root = new char[MAX_PATH]; BOOST_REGEX_NOEH_ASSERT(_root) _path = new char[MAX_PATH]; BOOST_REGEX_NOEH_ASSERT(_path) ptr = _path; *_path = 0; *_root = 0; ref = new file_iterator_ref(); BOOST_REGEX_NOEH_ASSERT(ref) ref->hf = _fi_invalid_handle; ref->count = 1; #ifndef BOOST_NO_EXCEPTIONS } catch(...) { delete[] _root; delete[] _path; delete ref; throw; } #endif } directory_iterator::directory_iterator(const char* wild) { _root = _path = 0; ref = 0; #ifndef BOOST_NO_EXCEPTIONS try{ #endif _root = new char[MAX_PATH]; BOOST_REGEX_NOEH_ASSERT(_root) _path = new char[MAX_PATH]; BOOST_REGEX_NOEH_ASSERT(_path) re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, wild)); ptr = _root; while(*ptr)++ptr; while((ptr > _root) && (*ptr != *_fi_sep) && (*ptr != *_fi_sep_alt))--ptr; if((ptr == _root) && ( (*ptr== *_fi_sep) || (*ptr==*_fi_sep_alt) ) ) { _root[1]='\0'; re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, _root)); } else { *ptr = 0; re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, _root)); if(*_path == 0) re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, ".")); re_detail::overflow_error_if_not_zero(re_detail::strcat_s(_path, MAX_PATH, _fi_sep)); } ptr = _path + std::strlen(_path); ref = new file_iterator_ref(); BOOST_REGEX_NOEH_ASSERT(ref) ref->count = 1; ref->hf = find_first_file(wild, ref->_data); if(ref->hf == _fi_invalid_handle) { *_path = 0; ptr = _path; } else { copy_find_file_result_with_overflow_check(ref->_data, ptr, MAX_PATH - (ptr - _path)); if(((ref->_data.dwFileAttributes & _fi_dir) == 0) || (std::strcmp(ptr, ".") == 0) || (std::strcmp(ptr, "..") == 0)) next(); } #ifndef BOOST_NO_EXCEPTIONS } catch(...) { delete[] _root; delete[] _path; delete ref; throw; } #endif } directory_iterator::~directory_iterator() { delete[] _root; delete[] _path; if(--(ref->count) == 0) { if(ref->hf != _fi_invalid_handle) FindClose(ref->hf); delete ref; } } directory_iterator::directory_iterator(const directory_iterator& other) { _root = _path = 0; ref = 0; #ifndef BOOST_NO_EXCEPTIONS try{ #endif _root = new char[MAX_PATH]; BOOST_REGEX_NOEH_ASSERT(_root) _path = new char[MAX_PATH]; BOOST_REGEX_NOEH_ASSERT(_path) re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, other._root)); re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, other._path)); ptr = _path + (other.ptr - other._path); ref = other.ref; #ifndef BOOST_NO_EXCEPTIONS } catch(...) { delete[] _root; delete[] _path; throw; } #endif ++(ref->count); } directory_iterator& directory_iterator::operator=(const directory_iterator& other) { re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, other._root)); re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, other._path)); ptr = _path + (other.ptr - other._path); if(--(ref->count) == 0) { if(ref->hf != _fi_invalid_handle) FindClose(ref->hf); delete ref; } ref = other.ref; ++(ref->count); return *this; } directory_iterator directory_iterator::operator++(int) { directory_iterator temp(*this); next(); return temp; } void directory_iterator::next() { if(ref->hf != _fi_invalid_handle) { bool cont = true; while(cont) { cont = find_next_file(ref->hf, ref->_data); if(cont && (ref->_data.dwFileAttributes & _fi_dir)) { if(is_not_current_or_parent_path_string(ref->_data)) break; } } if(!cont) { // end of sequence FindClose(ref->hf); ref->hf = _fi_invalid_handle; *_path = 0; ptr = _path; } else copy_find_file_result_with_overflow_check(ref->_data, ptr, MAX_PATH - (ptr - _path)); } } #ifdef BOOST_REGEX_FI_POSIX_DIR struct _fi_priv_data { char root[MAX_PATH]; char* mask; DIR* d; _fi_priv_data(const char* p); }; _fi_priv_data::_fi_priv_data(const char* p) { std::strcpy(root, p); mask = root; while(*mask) ++mask; while((mask > root) && (*mask != *_fi_sep) && (*mask != *_fi_sep_alt)) --mask; if(mask == root && ((*mask== *_fi_sep) || (*mask == *_fi_sep_alt)) ) { root[1] = '\0'; std::strcpy(root+2, p+1); mask = root+2; } else if(mask == root) { root[0] = '.'; root[1] = '\0'; std::strcpy(root+2, p); mask = root+2; } else { *mask = 0; ++mask; } } bool iswild(const char* mask, const char* name) { while(*mask && *name) { switch(*mask) { case '?': ++name; ++mask; continue; case '*': ++mask; if(*mask == 0) return true; while(*name) { if(iswild(mask, name)) return true; ++name; } return false; case '.': if(0 == *name) { ++mask; continue; } // fall through: default: if(BOOST_REGEX_FI_TRANSLATE(*mask) != BOOST_REGEX_FI_TRANSLATE(*name)) return false; ++mask; ++name; continue; } } if(*mask != *name) return false; return true; } unsigned _fi_attributes(const char* root, const char* name) { char buf[MAX_PATH]; // verify that we can not overflow: if(std::strlen(root) + std::strlen(_fi_sep) + std::strlen(name) >= MAX_PATH) return 0; int r; if( ( (root[0] == *_fi_sep) || (root[0] == *_fi_sep_alt) ) && (root[1] == '\0') ) r = (std::sprintf)(buf, "%s%s", root, name); else r = (std::sprintf)(buf, "%s%s%s", root, _fi_sep, name); if(r < 0) return 0; // sprintf failed DIR* d = opendir(buf); if(d) { closedir(d); return _fi_dir; } return 0; } _fi_find_handle _fi_FindFirstFile(const char* lpFileName, _fi_find_data* lpFindFileData) { _fi_find_handle dat = new _fi_priv_data(lpFileName); DIR* h = opendir(dat->root); dat->d = h; if(h != 0) { if(_fi_FindNextFile(dat, lpFindFileData)) return dat; closedir(h); } delete dat; return 0; } bool _fi_FindNextFile(_fi_find_handle dat, _fi_find_data* lpFindFileData) { dirent* d; do { d = readdir(dat->d); } while(d && !iswild(dat->mask, d->d_name)); if(d) { std::strcpy(lpFindFileData->cFileName, d->d_name); lpFindFileData->dwFileAttributes = _fi_attributes(dat->root, d->d_name); return true; } return false; } bool _fi_FindClose(_fi_find_handle dat) { closedir(dat->d); delete dat; return true; } #endif } // namespace re_detail } // namspace boost #endif // BOOST_REGEX_NO_FILEITER