/* Copyright (c) MediaArea.net SARL. All Rights Reserved.
*
* Use of this source code is governed by a zlib-style license that can
* be found in the License.txt file in the root of the source tree.
*/
//---------------------------------------------------------------------------
#include "ZenLib/PreComp.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include "ZenLib/Conf_Internal.h"
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#ifdef ZENLIB_USEWX
#include <wx/file.h>
#include <wx/filename.h>
#include <wx/utils.h>
#include <wx/dir.h>
#else //ZENLIB_USEWX
#ifdef ZENLIB_STANDARD
#undef WINDOWS
#endif
#ifdef WINDOWS
#undef __TEXT
#include <windows.h>
#ifdef WINDOWS_UWP
#include <wrl.h>
#include <windows.foundation.h>
#include <windows.storage.h>
#include <windows.storage.accesscache.h>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Foundation::Collections;
using namespace ABI::Windows::Storage;
#endif
#else
#include <sys/stat.h>
#include <sys/types.h>
#undef __TEXT //dirent include windows.h on Windows/Borland
#include <dirent.h>
#include <glob.h>
#endif
#endif //ZENLIB_USEWX
#include "ZenLib/Dir.h"
#include "ZenLib/File.h"
#include "ZenLib/FileName.h"
#include "ZenLib/OS_Utils.h"
//---------------------------------------------------------------------------
namespace ZenLib
{
//---------------------------------------------------------------------------
// Debug
#ifdef ZENLIB_DEBUG
#include <stdio.h>
#include <windows.h>
namespace ZenLib_Dir_Debug
{
FILE* F;
std::string Debug;
SYSTEMTIME st_In;
void Debug_Open(bool Out)
{
F=fopen("C:\\Temp\\ZenLib_Debug.txt", "a+t");
Debug.clear();
SYSTEMTIME st;
GetLocalTime( &st );
char Duration[100];
if (Out)
{
FILETIME ft_In;
if (SystemTimeToFileTime(&st_In, &ft_In))
{
FILETIME ft_Out;
if (SystemTimeToFileTime(&st, &ft_Out))
{
ULARGE_INTEGER UI_In;
UI_In.HighPart=ft_In.dwHighDateTime;
UI_In.LowPart=ft_In.dwLowDateTime;
ULARGE_INTEGER UI_Out;
UI_Out.HighPart=ft_Out.dwHighDateTime;
UI_Out.LowPart=ft_Out.dwLowDateTime;
ULARGE_INTEGER UI_Diff;
UI_Diff.QuadPart=UI_Out.QuadPart-UI_In.QuadPart;
FILETIME ft_Diff;
ft_Diff.dwHighDateTime=UI_Diff.HighPart;
ft_Diff.dwLowDateTime=UI_Diff.LowPart;
SYSTEMTIME st_Diff;
if (FileTimeToSystemTime(&ft_Diff, &st_Diff))
{
sprintf(Duration, "%02hd:%02hd:%02hd.%03hd", st_Diff.wHour, st_Diff.wMinute, st_Diff.wSecond, st_Diff.wMilliseconds);
}
else
strcpy(Duration, " ");
}
else
strcpy(Duration, " ");
}
else
strcpy(Duration, " ");
}
else
{
st_In=st;
strcpy(Duration, " ");
}
fprintf(F," %02hd:%02hd:%02hd.%03hd %s", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, Duration);
}
void Debug_Close()
{
Debug += "\r\n";
fwrite(Debug.c_str(), Debug.size(), 1, F); \
fclose(F);
}
}
using namespace ZenLib_Dir_Debug;
#define ZENLIB_DEBUG1(_NAME,_TOAPPEND) \
Debug_Open(false); \
Debug+=", ";Debug+=_NAME; \
_TOAPPEND; \
Debug_Close();
#define ZENLIB_DEBUG2(_NAME,_TOAPPEND) \
Debug_Open(true); \
Debug+=", ";Debug+=_NAME; \
_TOAPPEND; \
Debug_Close();
#else // ZENLIB_DEBUG
#define ZENLIB_DEBUG1(_NAME,_TOAPPEND)
#define ZENLIB_DEBUG2(_NAME,_TOAPPEND)
#endif // ZENLIB_DEBUG
//***************************************************************************
// Constructor/Destructor
//***************************************************************************
//***************************************************************************
// Open/Close
//***************************************************************************
ZtringList Dir::GetAllFileNames(const Ztring &Dir_Name_, dirlist_t Options)
{
ZENLIB_DEBUG1( "Dir GetAllFileNames",
Debug+=", Dir_Name="; Debug+=Ztring(Dir_Name_).To_UTF8(); Debug+=", Options="; Debug +=Ztring::ToZtring(Options).To_UTF8())
ZtringList ToReturn;
Ztring Dir_Name=Dir_Name_;
#ifdef ZENLIB_USEWX
int Flags=wxDIR_FILES | wxDIR_DIRS;
//Search for files
wxArrayString Liste;
wxFileName FullPath; FullPath=Dir_Name.c_str();
//-File
if (FullPath.FileExists())
{
FullPath.Normalize();
Liste.Add(FullPath.GetFullPath());
}
//-Directory
else if (FullPath.DirExists())
{
FullPath.Normalize();
wxDir::GetAllFiles(FullPath.GetFullPath(), &Liste, Ztring(), Flags);
}
//-WildCards
else
{
wxString FileName=FullPath.GetFullName();
FullPath.SetFullName(Ztring()); //Supress filename
FullPath.Normalize();
if (FullPath.DirExists())
wxDir::GetAllFiles(FullPath.GetPath(), &Liste, FileName, Flags);
}
//Compatible array
ToReturn.reserve(Liste.GetCount());
for (size_t Pos=0; Pos<Liste.GetCount(); Pos++)
ToReturn.push_back(Liste[Pos].c_str());
#else //ZENLIB_USEWX
#ifdef WINDOWS
#ifdef WINDOWS_UWP
//Ensure all slashs are converted to backslashs (WinRT file API don't like slashs)
Dir_Name.FindAndReplace(__T("/"), __T("\\"));
ComPtr<IStorageFolder> Folder;
if (FAILED(Get_Folder(HStringReference(Dir_Name.c_str(), (unsigned int)Dir_Name.size()), Folder)))
return ToReturn;
ComPtr<IAsyncOperation<IVectorView<IStorageItem*>* > > Async_GetItems;
ComPtr<IVectorView<IStorageItem*> > Items;
if (FAILED(Folder->GetItemsAsyncOverloadDefaultStartAndCount(&Async_GetItems)) ||
FAILED(Await(Async_GetItems)) ||
FAILED(Async_GetItems->GetResults(&Items)) ||
!Items)
return ToReturn;
unsigned int Size;
if (FAILED(Items->get_Size(&Size)))
return ToReturn;
for (unsigned int Pos=0; Pos<Size; ++Pos)
{
ComPtr<IStorageItem> Item;
if (FAILED(Items->GetAt(Pos, &Item)) || !Item)
continue;
HString File_Name_HString;
if (FAILED(Item->get_Name(File_Name_HString.GetAddressOf())))
continue;
Ztring File_Name(WindowsGetStringRawBuffer(File_Name_HString.Get(), NULL));
if (File_Name.empty() || (!(Options&Include_Hidden) && File_Name[0]==__T('.')))
continue;
tstring File_Name_Complete = Dir_Name + __T("\\") + File_Name;
boolean IsFile = FALSE;
boolean IsFolder = FALSE;
Item->IsOfType(StorageItemTypes_File, &IsFile);
Item->IsOfType(StorageItemTypes_Folder, &IsFolder);
if ((Options&Include_Files) && IsFile && ((Options&Include_Hidden) || File_Name[0] != __T('.')))
{
Add_Item_To_FUA(HStringReference(File_Name_Complete.c_str(), (unsigned int)File_Name_Complete.length()), Item);
ToReturn.push_back(File_Name_Complete);
}
else if ((Options&Include_Dirs) && IsFolder)
{
Add_Item_To_FUA(HStringReference(File_Name_Complete.c_str(), (unsigned int)File_Name_Complete.length()), Item);
ToReturn.push_back(File_Name_Complete);
}
if (IsFolder && Options&Parse_SubDirs)
ToReturn+=GetAllFileNames(File_Name_Complete, Options);
}
return ToReturn;
#else
//Is a dir?
if (Exists(Dir_Name))
Dir_Name+=__T("\\*");
//Path
Ztring Path=FileName::Path_Get(Dir_Name);
if (Path.empty())
{
DWORD Path_Size=GetFullPathName(Dir_Name.c_str(), 0, NULL, NULL);
Char* PathTemp=new Char[Path_Size+1];
if (GetFullPathName(Dir_Name.c_str(), Path_Size+1, PathTemp, NULL))
Path=FileName::Path_Get(PathTemp);
delete [] PathTemp;
}
#ifdef UNICODE
WIN32_FIND_DATAW FindFileDataW;
HANDLE hFind=FindFirstFileW(Dir_Name.c_str(), &FindFileDataW);
#else
WIN32_FIND_DATA FindFileData;
HANDLE hFind=FindFirstFile(Dir_Name.c_str(), &FindFileData);
#endif //UNICODE
if (hFind==INVALID_HANDLE_VALUE)
{
ZENLIB_DEBUG2( "Dir GetAllFileNames",
Debug+=", returns with files count="; Debug +=Ztring::ToZtring(ToReturn.size()).To_UTF8())
return ZtringList();
}
BOOL ReturnValue;
do
{
#ifdef UNICODE
Ztring File_Name(FindFileDataW.cFileName);
#else
Ztring File_Name(FindFileData.cFileName);
#endif //UNICODE
if (File_Name!=__T(".") && File_Name!=__T("..")) //Avoid . an ..
{
Ztring File_Name_Complete=Path+__T("\\")+File_Name;
if (Exists(File_Name_Complete))
{
if (Options&Include_Dirs)
ToReturn.push_back(File_Name_Complete); //A dir
if (Options&Parse_SubDirs)
ToReturn+=GetAllFileNames(File_Name_Complete, Options); //A SubDir
}
else if ((Options&Include_Files) && ((Options&Include_Hidden) || (!File_Name.empty() && File_Name[0]!=__T('.'))))
ToReturn.push_back(File_Name_Complete); //A file
}
#ifdef UNICODE
ReturnValue=FindNextFileW(hFind, &FindFileDataW);
#else
ReturnValue=FindNextFile(hFind, &FindFileData);
#endif //UNICODE
}
while (ReturnValue);
FindClose(hFind);
#endif
#else //WINDOWS
//A file?
if (File::Exists(Dir_Name))
{
ToReturn.push_back(Dir_Name); //TODO
return ToReturn;
}
//A dir?
if (!Dir::Exists(Dir_Name))
return ToReturn; //Does not exist
//open
#ifdef UNICODE
DIR* Dir=opendir(Dir_Name.To_Local().c_str());
#else
DIR* Dir=opendir(Dir_Name.c_str());
#endif //UNICODE
if (Dir)
{
//This is a dir
//Normalizing dir (the / at the end)
size_t Dir_Pos=Dir_Name.rfind(FileName_PathSeparator);
if (Dir_Pos==std::string::npos)
Dir_Name+=FileName_PathSeparator;
else if (Dir_Pos+Ztring(FileName_PathSeparator).size()!=Dir_Name.size())
Dir_Name+=FileName_PathSeparator;
struct dirent *DirEnt;
while((DirEnt=readdir(Dir))!=NULL)
{
//A file
Ztring File_Name(DirEnt->d_name);
if (File_Name!=__T(".") && File_Name!=__T("..")) //Avoid . an ..
{
Ztring File_Name_Complete=Dir_Name+File_Name;
if (Exists(File_Name_Complete))
{
if (Options&Parse_SubDirs)
ToReturn+=GetAllFileNames(File_Name_Complete, Options); //A SubDir
}
else if ((Options&Include_Hidden) || (!File_Name.empty() && File_Name[0]!=__T('.')))
ToReturn.push_back(File_Name_Complete); //A file
}
}
//Close it
closedir(Dir);
}
#if !defined(__ANDROID_API__) || __ANDROID_API__ >= 28
else
{
glob_t globbuf;
if (glob(Dir_Name.To_Local().c_str(), GLOB_NOSORT, NULL, &globbuf)==0)
{
for (size_t Pos=0; Pos<globbuf.gl_pathc; Pos++)
ToReturn.push_back(Ztring().From_Local(globbuf.gl_pathv[Pos]));
}
}
#endif
#endif
#endif //ZENLIB_USEWX
ZENLIB_DEBUG2( "Dir GetAllFileNames",
Debug+=", files count="; Debug +=Ztring::ToZtring(ToReturn.size()).To_UTF8())
return ToReturn;
}
//***************************************************************************
// Helpers
//***************************************************************************
//---------------------------------------------------------------------------
bool Dir::Exists(const Ztring &File_Name)
{
ZENLIB_DEBUG1( "Dir Exists",
Debug+=", Dir_Name="; Debug+=Ztring(File_Name).To_UTF8();)
#ifdef ZENLIB_USEWX
wxFileName FN(File_Name.c_str());
return FN.DirExists();
#else //ZENLIB_USEWX
#ifdef WINDOWS
#ifdef WINDOWS_UWP
//Ensure all slashs are converted to backslashs (WinRT file API don't like slashs)
Ztring File_Name_=File_Name;
File_Name_.FindAndReplace(__T("/"), __T("\\"));
//Try to access folder directly
ComPtr<IStorageFolder> Folder;
if (SUCCEEDED(Get_Folder(HStringReference(File_Name_.c_str(), (unsigned int)File_Name_.size()), Folder)))
return true;
//Try directory access methods
tstring Parent=FileName::Path_Get(File_Name_);
tstring Dir=FileName::Name_Get(File_Name_);
ComPtr<IStorageFolder> Parent_Folder;
if (FAILED(Get_Folder(HStringReference(Parent.c_str(), (unsigned int)Parent.size()), Parent_Folder)))
return false;
//IStorageFolder don't provide TryGetItemAsync
ComPtr<IStorageFolder2> Parent_Folder2;
if (FAILED(Parent_Folder->QueryInterface(IID_PPV_ARGS(&Parent_Folder2))) || !Parent_Folder2)
return false;
ComPtr<IAsyncOperation<IStorageItem*> > Async_GetItem;
ComPtr<IStorageItem> Item;
ComPtr<IStorageFolder> Child;
if (SUCCEEDED(Parent_Folder2->TryGetItemAsync(HStringReference(Dir.c_str(), (unsigned int)Dir.size()).Get(), &Async_GetItem)) &&
SUCCEEDED(Await(Async_GetItem)) &&
SUCCEEDED(Async_GetItem->GetResults(&Item)) &&
Item &&
SUCCEEDED(Item.As(&Child)))
return true;
return false;
#else
#ifdef UNICODE
DWORD FileAttributes=GetFileAttributesW(File_Name.c_str());
#else
DWORD FileAttributes=GetFileAttributes(File_Name.c_str());
#endif //UNICODE
ZENLIB_DEBUG2( "Dir Exists",
Debug+=", returns "; Debug +=Ztring::ToZtring(((FileAttributes!=INVALID_FILE_ATTRIBUTES) && (FileAttributes&FILE_ATTRIBUTE_DIRECTORY))?1:0).To_UTF8())
return ((FileAttributes!=INVALID_FILE_ATTRIBUTES) && (FileAttributes&FILE_ATTRIBUTE_DIRECTORY));
#endif
#else //WINDOWS
struct stat buffer;
int status;
#ifdef UNICODE
status=stat(File_Name.To_Local().c_str(), &buffer);
#else
status=stat(File_Name.c_str(), &buffer);
#endif //UNICODE
return status==0 && S_ISDIR(buffer.st_mode);
#endif
#endif //ZENLIB_USEWX
}
//---------------------------------------------------------------------------
bool Dir::Create(const Ztring &File_Name)
{
Ztring Parent=FileName::Path_Get(File_Name);
if (Parent.length() && !Exists(Parent))
{
if (!Create(Parent))
return false;
}
#ifdef ZENLIB_USEWX
return wxFileName::Mkdir(File_Name.c_str());
#else //ZENLIB_USEWX
#ifdef WINDOWS
#ifdef WINDOWS_UWP
CreationCollisionOption Collision_Option=CreationCollisionOption_FailIfExists;
//Ensure all slashs are converted to backslashs (WinRT file API don't like slashs)
Parent.FindAndReplace(__T("/"), __T("\\"));
//Split folder and parent
Ztring Dir=FileName::Name_Get(File_Name);
//Split folder and parent
size_t Last_Separator=File_Name.rfind(__T("\\"));
//Open parent folder
ComPtr<IStorageFolder> Folder;
if (FAILED(Get_Folder(HStringReference(Parent.c_str(), (unsigned int)Parent.size()), Folder)))
return false;
//Create folder
ComPtr<IAsyncOperation<StorageFolder*> > Async_Create;
ComPtr<IStorageFolder> New;
if (FAILED(Folder->CreateFolderAsync(HStringReference(Dir.c_str(), (unsigned int)Dir.size()).Get(), Collision_Option, &Async_Create)) ||
FAILED(Await(Async_Create)) ||
FAILED(Async_Create->GetResults(&New)) ||
!New)
return false;
return true;
#else
#ifdef UNICODE
return CreateDirectoryW(File_Name.c_str(), NULL)!=0;
#else
return CreateDirectory(File_Name.c_str(), NULL)!=0;
#endif //UNICODE
#endif
#else //WINDOWS
return mkdir(File_Name.To_Local().c_str(), 0700)==0;
#endif //WINDOWS
#endif //ZENLIB_USEWX
}
//***************************************************************************
// GetAllFileNames
//***************************************************************************
#if defined WINDOWS && !defined WINDOWS_UWP
class GetAllFileNames_Private
{
public:
Ztring Dir_Name;
Ztring Path;
Dir::dirlist_t Options;
HANDLE hFind;
#ifdef UNICODE
WIN32_FIND_DATAW FindFileDataW;
#else
WIN32_FIND_DATA FindFileData;
#endif //UNICODE
GetAllFileNames_Private()
: hFind(INVALID_HANDLE_VALUE)
{
}
};
//---------------------------------------------------------------------------
GetAllFileNames::GetAllFileNames()
: p(NULL)
{
}
//---------------------------------------------------------------------------
GetAllFileNames::~GetAllFileNames()
{
Close();
}
//---------------------------------------------------------------------------
void GetAllFileNames::Start (const Ztring &Dir_Name_, Dir::dirlist_t Options_)
{
ZENLIB_DEBUG1( "GetAllFileNames Start",
Debug+=", Dir_Name="; Debug+=Ztring(Dir_Name_).To_UTF8(); Debug+=", Options="; Debug +=Ztring::ToZtring(Options_).To_UTF8())
delete p; p=new GetAllFileNames_Private;
p->Dir_Name=Dir_Name_;
p->Options=Options_;
#ifdef WINDOWS
//Is a dir?
if (Dir::Exists(p->Dir_Name))
p->Dir_Name+=__T("\\*");
//Path
p->Path=FileName::Path_Get(p->Dir_Name);
if (p->Path.empty())
{
DWORD Path_Size=GetFullPathName(p->Dir_Name.c_str(), 0, NULL, NULL);
Char* PathTemp=new Char[Path_Size+1];
if (GetFullPathName(p->Dir_Name.c_str(), Path_Size+1, PathTemp, NULL))
p->Path=FileName::Path_Get(PathTemp);
delete [] PathTemp;
}
#else //WINDOWS
#endif
ZENLIB_DEBUG2( "GetAllFileNames Start",
)
}
bool GetAllFileNames::Next (Ztring& Name)
{
if (!p)
return false;
ZENLIB_DEBUG1( "GetAllFileNames Next",
Debug+=", Dir_Name="; Debug+=Ztring(p->Dir_Name).To_UTF8())
#ifdef WINDOWS
for (;;)
{
if (p->hFind==INVALID_HANDLE_VALUE)
{
#ifdef UNICODE
p->hFind=FindFirstFileW(p->Dir_Name.c_str(), &p->FindFileDataW);
#else
p->hFind=FindFirstFile(p->Dir_Name.c_str(), &p->FindFileData);
#endif //UNICODE
if (p->hFind==INVALID_HANDLE_VALUE)
break;
}
else
{
BOOL ReturnValue;
#ifdef UNICODE
ReturnValue=FindNextFileW(p->hFind, &p->FindFileDataW);
#else
ReturnValue=FindNextFile(p->hFind, &p->FindFileData);
#endif //UNICODE
if (!ReturnValue)
break;
}
#ifdef UNICODE
Ztring File_Name(p->FindFileDataW.cFileName);
#else
Ztring File_Name(p->FindFileData.cFileName);
#endif //UNICODE
if (File_Name!=__T(".") && File_Name!=__T("..")) //Avoid . an ..
{
bool IsOk=false;
#ifdef UNICODE
if (p->FindFileDataW.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
#else
if (p->FindFileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
#endif //UNICODE
{
if (p->Options&Dir::Include_Dirs)
IsOk=true; //A dir
}
else if ((p->Options&Dir::Include_Files) && ((p->Options&Dir::Include_Hidden) || (!File_Name.empty() && File_Name[0]!=__T('.'))))
IsOk=true; //A file
if (IsOk)
{
Name=p->Path+__T("\\")+File_Name;
ZENLIB_DEBUG2( "GetAllFileNames Next",
Debug+=", File_Name="; Debug +=Name.To_UTF8())
return true;
}
}
}
#else //WINDOWS
#endif
Close();
return false;
}
void GetAllFileNames::Close ()
{
if (!p)
return;
ZENLIB_DEBUG1( "GetAllFileNames Close",
Debug+=", Dir_Name="; Debug+=Ztring(p->Dir_Name).To_UTF8())
FindClose(p->hFind); p->hFind=INVALID_HANDLE_VALUE;
delete p; p=NULL;
ZENLIB_DEBUG2( "GetAllFileNames Close",
)
}
#endif //WINDOWS && !WINDOWS_UWP
//***************************************************************************
//
//***************************************************************************
} //namespace
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: Options, FindFileDataW.