CyberEngineMkIII
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
CYBWin32Path.cpp
Go to the documentation of this file.
1 #include "CYB.hpp"
3 
4 using namespace CYB::Platform::Win32;
5 using namespace CYB::API::String;
6 
8  if (ADirectory != SystemPath::EXECUTABLE_IMAGE
9  && ADirectory != SystemPath::EXECUTABLE
10  && ADirectory != SystemPath::RESOURCE
11  && ADirectory != SystemPath::TEMPORARY
12  && ADirectory != SystemPath::USER
13  && ADirectory != SystemPath::WORKING)
15  auto& MM(Core().FModuleManager);
16  switch (ADirectory) {
17  case SystemPath::EXECUTABLE_IMAGE:
18  case SystemPath::EXECUTABLE: {
19  auto Module(MM.Call<Modules::Kernel32::GetModuleHandleW>(nullptr));
20  if (Module != nullptr) {
21  wchar_t Buffer[MAX_PATH];
22  if (MM.Call<Modules::Kernel32::GetModuleFileNameW>(Module, Buffer, DWORD(MAX_PATH)) != 0)
23  if (ADirectory == SystemPath::EXECUTABLE) {
24  if (MM.Call<Modules::ShellAPI::PathRemoveFileSpecW>(Buffer) != 0)
25  return API::String::UTF16::ToUTF8(Buffer);
27  }
28  return API::String::UTF16::ToUTF8(Buffer);
29  }
31  }
32  case SystemPath::RESOURCE:
33  return GetResourceDirectory();
34  case SystemPath::TEMPORARY: {
35  API::String::UTF8 Result;
36  {
37  wchar_t Buffer[MAX_PATH];
38  if (MM.Call<Modules::Kernel32::GetTempPathW>(Win32::DWORD(MAX_PATH), Buffer) == 0)
40  Result = API::String::UTF16::ToUTF8(Buffer);
41  }
43  bool Throw(false);
45  try {
46  CreateDirectory(Result);
47  }
48  catch (Exception::SystemData AException) {
49  Throw = true;
50  ThrowCode = static_cast<Exception::SystemData::ErrorCode>(AException.FErrorCode);
52  if(ThrowCode == Exception::SystemData::STREAM_NOT_WRITABLE)
54  }
55  if(Throw)
56  throw Exception::SystemData(ThrowCode);
57  return Result;
58  }
59  case SystemPath::WORKING:
60  {
61  wchar_t Buffer[MAX_PATH];
62  if (MM.Call<Modules::Kernel32::GetCurrentDirectoryW>(Win32::DWORD(MAX_PATH), Buffer) == 0)
64  return API::String::UTF16::ToUTF8(Buffer);
65  }
66  case SystemPath::USER:
67  {
68  struct AutoFreeBuffer {
69  private:
70  wchar_t* const FBuffer;
71  public:
72  AutoFreeBuffer(wchar_t* const ABuffer) :
73  FBuffer(ABuffer)
74  {}
75  ~AutoFreeBuffer() {
76  Core().FModuleManager.Call<Modules::Ole32::CoTaskMemFree>(FBuffer);
77  }
78  };
79  wchar_t* Buffer;
80  //https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx
81  //GUID for roaming app data
82  if (MM.Call<Modules::Shell::SHGetKnownFolderPath>(GUID{ 0xF1B32785, 0x6FBA, 0x4FCF, 0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91 }, DWORD(0), nullptr, &Buffer) != S_OK)
84 
85  AutoFreeBuffer AFB(Buffer);
86  auto Result(API::String::UTF16::ToUTF8(Buffer));
87  return Result;
88  }
89  default:
90  UNREACHABLE; //HCF is too indirect for coverage
91  }
92 }
93 
95  API::String::UTF16 As16(APath);
96  if (CheckDirectoryExists(As16) != 1) {
97  if (Core().FModuleManager.Call<Modules::Kernel32::CreateDirectoryW>(As16.WString(), nullptr) == 0
98  && Core().FModuleManager.Call<Modules::Kernel32::GetLastError>() != ERROR_ALREADY_EXISTS)
100  }
101 }
102 
104  API::String::UTF16 As16(APath);
105  if (Core().FModuleManager.Call<Modules::Kernel32::RemoveDirectoryW>(As16.WString()) == FALSE) {
106  const auto Error(Core().FModuleManager.Call<Modules::Kernel32::GetLastError>());
107  switch (Error) {
108  case ERROR_FILE_NOT_FOUND:
109  break; //contract fufilled
110  case ERROR_DIR_NOT_EMPTY:
112  default:
114  }
115  }
116 }
117 
119  API::String::UTF16 As16(APath);
120  auto& MM(Core().FModuleManager);
121  if (MM.Call<Modules::Kernel32::DeleteFileW>(As16.WString()) == FALSE) {
122  const auto Error(MM.Call<Modules::Kernel32::GetLastError>());
123  switch (Error) {
124  case ERROR_FILE_NOT_FOUND:
125  break; //contract fufilled
126  case ERROR_ACCESS_DENIED: {
127  //try once more with no RO attribute
128  WIN32_FILE_ATTRIBUTE_DATA Attributes;
129  const auto Result(MM.Call<Modules::Kernel32::GetFileAttributesExW>(As16.WString(), GetFileExInfoStandard, &Attributes));
130  if (Result != 0) {
131  Attributes.dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;
132  if (MM.Call<Modules::Kernel32::SetFileAttributesW>(As16.WString(), Attributes.dwFileAttributes) != FALSE && MM.Call<Modules::Kernel32::DeleteFileW>(As16.WString()) != FALSE)
133  break;
134  }
136  }
137  default:
139  }
140  }
141 }
142 
144  API::String::UTF16 As16(APath);
145  wchar_t OutputBuffer[MAX_PATH];
146  if (Core().FModuleManager.Call<Modules::ShellAPI::PathCanonicalizeW>(OutputBuffer, As16.WString()) == FALSE)
148  APath = API::String::UTF16::ToUTF8(OutputBuffer);
149 }
150 
152  API::String::UTF16 As16;
153  const bool Local(&APath == &FPath);
154  if (!Local)
155  As16 = API::String::UTF16(APath);
156  const API::String::UTF16& Ref(Local ? FWidePath : As16);
157 
158  return Core().FModuleManager.Call<Modules::ShellAPI::PathFileExistsW>(Ref.WString()) == TRUE;
159 }
160 
162  FWidePath = API::String::UTF16(APath);
163  FPath = std::move(APath);
164 }
165 
167  WIN32_FILE_ATTRIBUTE_DATA Attributes;
168  const auto Result(Core().FModuleManager.Call<Modules::Kernel32::GetFileAttributesExW>(APath.WString(), GetFileExInfoStandard, &Attributes));
169  if (Result == 0)
170  return -1;
171  return ((Attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) > 0) ? 1 : 0;
172 }
173 
175  const auto Result(CheckDirectoryExists(FWidePath));
176  if (Result == -1) {
177  const auto Error(Core().FModuleManager.Call<Modules::Kernel32::GetLastError>());
178  if (Error == ERROR_ACCESS_DENIED || Error == ERROR_SHARING_VIOLATION)
181  }
182  return Result == 1;
183 }
184 
186  //docs say it has to be MAX_PATH
187  //examples say otherwise, but this function is deprecated so lets humor them
188  wchar_t Buffer[MAX_PATH];
189  API::Assert::Equal(FWidePath.RawLength() % 2, 0);
190  std::copy(FWidePath.WString(), FWidePath.WString() + FWidePath.RawLength(), Buffer);
191 
192  //This won't work with '/' chars so convert them here
193  //Only the last one though because that's all we need
194  for (auto I(FWidePath.RawLength() / 2); I >= 0 ; --I)
195  if (Buffer[I] == L'/') {
196  Buffer[I] = L'\\';
197  break;
198  }
199  auto& MM(Core().FModuleManager);
200  const auto Result1(MM.Call<Modules::ShellAPI::PathIsRootW>(Buffer));
201  if (Result1 != FALSE)
203 
204  const auto Result2(MM.Call<Modules::ShellAPI::PathRemoveFileSpecW>(Buffer));
205  if (Result2 == 0)
206  throw Exception::SystemData(Exception::SystemData::STREAM_NOT_READABLE); //this doesn't seem to happen irl but whatever
207  SetPath(UTF16::ToUTF8(Buffer));
208 }
209 
211  const auto Result(Core().FModuleManager.Call<Modules::ShellAPI::PathFindFileNameW>(const_cast<wchar_t*>(FWidePath.WString())));
212  if (*Result == 0)
214  return UTF16::ToUTF8(Result);
215 }
216 
218  const auto File(Core().FModuleManager.Call<Modules::ShellAPI::PathFindFileNameW>(const_cast<wchar_t*>(FWidePath.WString()))),
219  Extension(Core().FModuleManager.Call<Modules::ShellAPI::PathFindExtensionW>(const_cast<wchar_t*>(FWidePath.WString())));
220  if (*File == 0)
222  if (*Extension == 0)
223  return UTF16::ToUTF8(File);
224 
225  wchar_t Buffer[MAX_PATH];
226  std::memset(Buffer, 0, sizeof(Buffer));
227  std::copy(File, Extension, Buffer);
228 
229  return UTF16::ToUTF8(Buffer);
230 }
231 
232 
233 //DirectoryEntry
234 
236  FOriginalPath(APath),
237  FPathListing(nullptr)
238 {
239  WIN32_FIND_DATA FindData;
240  {
242  FFindHandle = Core().FModuleManager.Call<Modules::Kernel32::FindFirstFileW>(Query.WString(), &FindData);
243  }
244  if (FFindHandle == INVALID_HANDLE_VALUE) {
245  const auto Error(Core().FModuleManager.Call<Modules::Kernel32::GetLastError>());
246  switch (Error) {
247  case ERROR_FILE_NOT_FOUND:
248  break; //can really only happen if a drive is enumed and is empty
249  case ERROR_ACCESS_DENIED:
251  default:
253  }
254  }
255  else
256  AssignOrRecurse(std::move(FindData));
257 }
258 
260  Core().FModuleManager.Call<Modules::Kernel32::FindClose>(FFindHandle);
261 }
262 
264  WIN32_FIND_DATA FindData;
265  if (Core().FModuleManager.Call<Modules::Kernel32::FindNextFileW>(FFindHandle, &FindData) == 0)
266  FPathListing = API::Interop::Object<API::Path>(nullptr);
267  else
268  AssignOrRecurse(std::move(FindData));
269 }
270 
272  UTF8 Conversion;
273  {
274  auto FindData(std::move(AFindData));
275  Conversion = UTF16::ToUTF8(FindData.cFileName);
276  if (Conversion == Static(u8".") || Conversion == Static(u8"..")) {
277  operator++();
278  return;
279  }
280  }
282 }
283 
285  return FWidePath;
286 }
void AssignOrRecurse(Win32::WIN32_FIND_DATA &&AFindData)
Assign the current data to FPathListing if it is not '.' or '..'.
A variable length UTF-8 string.
Definition: UTF8String.hpp:8
Template type for wrapping pointers and treating them as objects. Only works with CyberEngine interfa...
Definition: Object.hpp:10
API::Interop::Context & Context(void) noexcept
Get the API's Context.
API::String::UTF8 Name(void) const finaloverride
Get the name of the file without any directory prefixes or extensions. Equivalent to FullFileName and...
static const char *const FTempPathName
The directory in the temp folder to use.
static API::String::UTF8 LocateDirectory(const SystemPath ADirectory)
Get the string path of a SystemPath.
Definition: CYBWin32Path.cpp:7
void operator++(void) finaloverride
Advance the iterator.
static void Evaluate(API::String::UTF8 &APath)
Evaluates '..' and '.' references within the path.
bool IsDirectory(void) const finaloverride
Check if the current path is a directory.
Contains the basic File interface. Does not perform locking of any kind, be aware of possible race co...
Definition: CYBFile.hpp:6
A string pointing to unchanging data in the stack above it or the data segment. Must have UTF-8 encod...
Definition: StaticString.hpp:7
static void CreateDirectory(const API::String::UTF8 &APath)
Ensure the existance of a single directory. Path's before it must exist.
UTF-16 String enabled only under windows.
Platform::Modules::Manager FModuleManager
Loads and contains required modules.
Definition: CYBCore.hpp:20
Object< AObject > ConstructObject(AArgs &&...AArguments)
Allocates the Object specified by AObject using a specified Constructor.
const API::String::UTF16 & WidePath(void) const noexcept
Accessor for other Win32 implementations that require the UTF16 Path.
SystemPath
Starting points for creating paths.
Definition: Path.hpp:15
Used for manipulating Paths. Paths will always exist either as a file or directory. Paths are '/' delimited when forming though may not be while retrieving. File names ".." will ascend a directory and '.' represents a no-op.
Definition: Path.hpp:9
static UTF8 ToUTF8(const wchar_t *AWString)
Create a new UTF8 string given a wide char array.
const unsigned int FErrorCode
The assigned error code.
Definition: Exception.hpp:18
const System::Path & FOriginalPath
The Path of the directory being enumerated.
static void DeleteFile(const API::String::UTF8 &APath)
Ensure the non-existance of a single file. Path's before it must exist. Directory must be empty...
bool Verify(const API::String::UTF8 &APath) const
Verifys the path pointed to exists.
DirectoryEntry(const System::Path &APath)
Begin the directory listing operation of APath.
A previously valid path has become invalidated, most likely due to deletion.
Definition: Exception.hpp:76
Exceptions caused by external call failures or invalid external data. Only classifies ones that can p...
Definition: Exception.hpp:65
static void Equal(const AType &ALHS, const AType &ARHS) noexcept
Equivalence assertion function. May not be evaluated.
API::String::UTF16 FWidePath
The UTF16 string.
A heap has no block large enough for a requested allocation and expansion failed. ...
Definition: Exception.hpp:74
Allocator & FAllocator
The Allocator.
Definition: Context.hpp:11
API::String::UTF8 FullName(void) const finaloverride
Get the name of the file without any prefixes. Equivalent to FileName and Extension if the name does ...
void NavigateToParentDirectory(void) finaloverride
Navigate the path to the parent directory. Does NOT work on invalidated paths.
static int CheckDirectoryExists(const API::String::UTF16 &APath) noexcept
Try to check for the existence of a directory.
const wchar_t * WString(void) const noexcept
Get the underlying const wide char array.
void SetPath(API::String::UTF8 &&APath)
Sets the current Path string.
Generic error for read failures. See functions for further documentation.
Definition: Exception.hpp:72
Precompiled header for inter-engine operations.
Win32::HANDLE FFindHandle
The Win32 find handle.
static const String::Static DirectorySeparatorChar(void) noexcept
Get the standardized UTF-8 directory separator string.
Definition: Path.hpp:74
static void DeleteDirectory(const API::String::UTF8 &APath)
Ensure the non-existance of a single directory. Path's before it must exist. Directory must be empty...
Engine::Core & Core(void) noexcept
Retrieve the Core singleton.
Definition: CYBCore.cpp:69
Used for manipulating Paths. Paths will always exist either as a file or directory. Paths are '/' delimited when forming though may not be while retrieving. File names ".." will ascend a directory and '.' represents a no-op.
Definition: CYBPath.hpp:10
A system path could not be retrieved.
Definition: Exception.hpp:79
Exceptions that are thrown internally in the engine that the should never see, these are a superset o...
Definition: Exception.hpp:104
Tried to delete a non-empty directory.
Definition: Exception.hpp:69
ErrorCode
The error code of the exception.
Definition: Exception.hpp:68
auto Call(AArgs &&...AArguments)
Call a loaded function.
Exceptions indicating an API contract violation. Should not be anticipated.
Definition: Exception.hpp:32
Template for defining the types of parameters for engine object constructors with multiple arguments...
Definition: Constructor.hpp:11
#define UNREACHABLE
Used for hardcore unreachable code paths when Assert::HCF is not enough. Should generally be avoided ...
Definition: Assert.hpp:27
Generic error for write failures. See functions for further documentation.
Definition: Exception.hpp:73
~DirectoryEntry() finaloverride
See Default Constructors and Destructor.
An operation was attempted with an invalid enum code.
Definition: Exception.hpp:36