Plasma Engine  2.0
Loading...
Searching...
No Matches
OSFile_Posix.h
1#include <Foundation/FoundationPCH.h>
2PL_FOUNDATION_INTERNAL_HEADER
3
4#include <Foundation/IO/OSFile.h>
5#include <Foundation/Logging/Log.h>
6#include <Foundation/Threading/ThreadUtils.h>
7#include <Foundation/Utilities/CommandLineUtils.h>
8#include <errno.h>
9#include <stdio.h>
10#include <sys/stat.h>
11
12#if PL_ENABLED(PL_PLATFORM_WINDOWS)
13# include <direct.h>
14# define PL_USE_OLD_POSIX_FUNCTIONS PL_ON
15#else
16# include <dirent.h>
17# include <fnmatch.h>
18# include <pwd.h>
19# include <sys/file.h>
20# include <sys/types.h>
21# include <unistd.h>
22# define PL_USE_OLD_POSIX_FUNCTIONS PL_OFF
23#endif
24
25#if PL_ENABLED(PL_PLATFORM_OSX)
26# include <CoreFoundation/CoreFoundation.h>
27#endif
28
29#if PL_ENABLED(PL_PLATFORM_ANDROID)
30# include <Foundation/Basics/Platform/Android/AndroidJni.h>
31# include <Foundation/Basics/Platform/Android/AndroidUtils.h>
32# include <android_native_app_glue.h>
33#endif
34
35#ifndef PATH_MAX
36# define PATH_MAX 1024
37#endif
38
39plResult plOSFile::InternalOpen(plStringView sFile, plFileOpenMode::Enum OpenMode, plFileShareMode::Enum FileShareMode)
40{
41 plStringBuilder sFileCopy = sFile;
42 const char* szFile = sFileCopy;
43
44#if PL_DISABLED(PL_PLATFORM_WINDOWS_UWP) // UWP does not support these functions
45 int fd = -1;
46 switch (OpenMode)
47 {
48 // O_CLOEXEC = don't forward to child processes
50 fd = open(szFile, O_RDONLY | O_CLOEXEC);
51 break;
54 fd = open(szFile, O_CREAT | O_WRONLY | O_CLOEXEC, 0644);
55 break;
56 default:
57 break;
58 }
59
60 if (FileShareMode == plFileShareMode::Default)
61 {
62 if (OpenMode == plFileOpenMode::Read)
63 {
64 FileShareMode = plFileShareMode::SharedReads;
65 }
66 else
67 {
68 FileShareMode = plFileShareMode::Exclusive;
69 }
70 }
71
72 if (fd == -1)
73 {
74 return PL_FAILURE;
75 }
76
77 const int iSharedMode = (FileShareMode == plFileShareMode::Exclusive) ? LOCK_EX : LOCK_SH;
78 const plTime sleepTime = plTime::MakeFromMilliseconds(20);
79 plInt32 iRetries = m_bRetryOnSharingViolation ? 20 : 1;
80
81 while (flock(fd, iSharedMode | LOCK_NB /* do not block */) != 0)
82 {
83 int errorCode = errno;
84 iRetries--;
85 if (iRetries == 0 || errorCode != EWOULDBLOCK)
86 {
87 // error, could not get a lock
88 plLog::Error("Failed to get a {} lock for file {}, error {}", (FileShareMode == plFileShareMode::Exclusive) ? "Exculsive" : "Shared", szFile, errno);
89 close(fd);
90 return PL_FAILURE;
91 }
92 plThreadUtils::Sleep(sleepTime);
93 }
94
95 switch (OpenMode)
96 {
98 m_FileData.m_pFileHandle = fdopen(fd, "rb");
99 break;
101 if (ftruncate(fd, 0) < 0)
102 {
103 close(fd);
104 return PL_FAILURE;
105 }
106 m_FileData.m_pFileHandle = fdopen(fd, "wb");
107 break;
109 m_FileData.m_pFileHandle = fdopen(fd, "ab");
110
111 // in append mode we need to set the file pointer to the end explicitly, otherwise GetFilePosition might return 0 the first time
112 if (m_FileData.m_pFileHandle != nullptr)
113 InternalSetFilePosition(0, plFileSeekMode::FromEnd);
114
115 break;
116 default:
117 break;
118 }
119
120 if (m_FileData.m_pFileHandle == nullptr)
121 {
122 close(fd);
123 }
124
125#else
126
127 switch (OpenMode)
128 {
130 m_FileData.m_pFileHandle = fopen(szFile, "rb");
131 break;
133 m_FileData.m_pFileHandle = fopen(szFile, "wb");
134 break;
136 m_FileData.m_pFileHandle = fopen(szFile, "ab");
137
138 // in append mode we need to set the file pointer to the end explicitly, otherwise GetFilePosition might return 0 the first time
139 if (m_FileData.m_pFileHandle != nullptr)
140 InternalSetFilePosition(0, plFileSeekMode::FromEnd);
141
142 break;
143 default:
144 break;
145 }
146#endif
147
148 if (m_FileData.m_pFileHandle == nullptr)
149 {
150 return PL_FAILURE;
151 }
152
153 // lock will be released automatically when the file is closed
154 return PL_SUCCESS;
155}
156
157void plOSFile::InternalClose()
158{
159 fclose(m_FileData.m_pFileHandle);
160}
161
162plResult plOSFile::InternalWrite(const void* pBuffer, plUInt64 uiBytes)
163{
164 const plUInt32 uiBatchBytes = 1024 * 1024 * 1024; // 1 GB
165
166 // first write out all the data in 1GB batches
167 while (uiBytes > uiBatchBytes)
168 {
169 if (fwrite(pBuffer, 1, uiBatchBytes, m_FileData.m_pFileHandle) != uiBatchBytes)
170 {
171 plLog::Error("fwrite 1GB failed for '{}'", m_sFileName);
172 return PL_FAILURE;
173 }
174
175 uiBytes -= uiBatchBytes;
176 pBuffer = plMemoryUtils::AddByteOffset(pBuffer, uiBatchBytes);
177 }
178
179 if (uiBytes > 0)
180 {
181 const plUInt32 uiBytes32 = static_cast<plUInt32>(uiBytes);
182
183 if (fwrite(pBuffer, 1, uiBytes32, m_FileData.m_pFileHandle) != uiBytes)
184 {
185 plLog::Error("fwrite failed for '{}'", m_sFileName);
186 return PL_FAILURE;
187 }
188 }
189
190 return PL_SUCCESS;
191}
192
193plUInt64 plOSFile::InternalRead(void* pBuffer, plUInt64 uiBytes)
194{
195 plUInt64 uiBytesRead = 0;
196
197 const plUInt32 uiBatchBytes = 1024 * 1024 * 1024; // 1 GB
198
199 // first write out all the data in 1GB batches
200 while (uiBytes > uiBatchBytes)
201 {
202 const plUInt64 uiReadThisTime = fread(pBuffer, 1, uiBatchBytes, m_FileData.m_pFileHandle);
203 uiBytesRead += uiReadThisTime;
204
205 if (uiReadThisTime != uiBatchBytes)
206 return uiBytesRead;
207
208 uiBytes -= uiBatchBytes;
209 pBuffer = plMemoryUtils::AddByteOffset(pBuffer, uiBatchBytes);
210 }
211
212 if (uiBytes > 0)
213 {
214 const plUInt32 uiBytes32 = static_cast<plUInt32>(uiBytes);
215
216 uiBytesRead += fread(pBuffer, 1, uiBytes32, m_FileData.m_pFileHandle);
217 }
218
219 return uiBytesRead;
220}
221
222plUInt64 plOSFile::InternalGetFilePosition() const
223{
224#if PL_ENABLED(PL_USE_OLD_POSIX_FUNCTIONS)
225 return static_cast<plUInt64>(ftell(m_FileData.m_pFileHandle));
226#else
227 return static_cast<plUInt64>(ftello(m_FileData.m_pFileHandle));
228#endif
229}
230
231void plOSFile::InternalSetFilePosition(plInt64 iDistance, plFileSeekMode::Enum Pos) const
232{
233#if PL_ENABLED(PL_USE_OLD_POSIX_FUNCTIONS)
234 switch (Pos)
235 {
237 PL_VERIFY(fseek(m_FileData.m_pFileHandle, (long)iDistance, SEEK_SET) == 0, "Seek Failed");
238 break;
240 PL_VERIFY(fseek(m_FileData.m_pFileHandle, (long)iDistance, SEEK_END) == 0, "Seek Failed");
241 break;
243 PL_VERIFY(fseek(m_FileData.m_pFileHandle, (long)iDistance, SEEK_CUR) == 0, "Seek Failed");
244 break;
245 }
246#else
247 switch (Pos)
248 {
250 PL_VERIFY(fseeko(m_FileData.m_pFileHandle, iDistance, SEEK_SET) == 0, "Seek Failed");
251 break;
253 PL_VERIFY(fseeko(m_FileData.m_pFileHandle, iDistance, SEEK_END) == 0, "Seek Failed");
254 break;
256 PL_VERIFY(fseeko(m_FileData.m_pFileHandle, iDistance, SEEK_CUR) == 0, "Seek Failed");
257 break;
258 }
259#endif
260}
261
262// this might not be defined on Windows
263#ifndef S_ISDIR
264# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
265#endif
266
267bool plOSFile::InternalExistsFile(plStringView sFile)
268{
269 struct stat sb;
270 return (stat(plString(sFile), &sb) == 0 && !S_ISDIR(sb.st_mode));
271}
272
273bool plOSFile::InternalExistsDirectory(plStringView sDirectory)
274{
275 struct stat sb;
276 return (stat(plString(sDirectory), &sb) == 0 && S_ISDIR(sb.st_mode));
277}
278
279plResult plOSFile::InternalDeleteFile(plStringView sFile)
280{
281#if PL_ENABLED(PL_PLATFORM_WINDOWS)
282 int iRes = _unlink(plString(sFile));
283#else
284 int iRes = unlink(plString(sFile));
285#endif
286
287 if (iRes == 0 || (iRes == -1 && errno == ENOENT))
288 return PL_SUCCESS;
289
290 return PL_FAILURE;
291}
292
293plResult plOSFile::InternalDeleteDirectory(plStringView sDirectory)
294{
295#if PL_ENABLED(PL_PLATFORM_WINDOWS)
296 int iRes = _rmdir(plString(sDirectory));
297#else
298 int iRes = rmdir(plString(sDirectory));
299#endif
300
301 if (iRes == 0 || (iRes == -1 && errno == ENOENT))
302 return PL_SUCCESS;
303
304 return PL_FAILURE;
305}
306
307plResult plOSFile::InternalCreateDirectory(plStringView sDirectory)
308{
309 // handle drive letters as always successful
310 if (plStringUtils::GetCharacterCount(sDirectory.GetStartPointer(), sDirectory.GetEndPointer()) <= 1) // '/'
311 return PL_SUCCESS;
312
313#if PL_ENABLED(PL_PLATFORM_WINDOWS)
314 int iRes = _mkdir(plString(sDirectory));
315#else
316 int iRes = mkdir(plString(sDirectory), 0777);
317#endif
318
319 if (iRes == 0 || (iRes == -1 && errno == EEXIST))
320 return PL_SUCCESS;
321
322 // If we were not allowed to access the folder but it alreay exists, we treat the operation as successful.
323 // Note that this is espcially relevant for calls to plOSFile::CreateDirectoryStructure where we may call mkdir on top level directories that are
324 // not accessible.
325 if (errno == EACCES && InternalExistsDirectory(sDirectory))
326 return PL_SUCCESS;
327
328 return PL_FAILURE;
329}
330
331plResult plOSFile::InternalMoveFileOrDirectory(plStringView sDirectoryFrom, plStringView sDirectoryTo)
332{
333 if (rename(plString(sDirectoryFrom), plString(sDirectoryTo)) != 0)
334 {
335 return PL_FAILURE;
336 }
337 return PL_SUCCESS;
338}
339
340#if PL_ENABLED(PL_SUPPORTS_FILE_STATS) && PL_DISABLED(PL_PLATFORM_WINDOWS_UWP)
341plResult plOSFile::InternalGetFileStats(plStringView sFileOrFolder, plFileStats& out_Stats)
342{
343 struct stat tempStat;
344 int iRes = stat(plString(sFileOrFolder), &tempStat);
345
346 if (iRes != 0)
347 return PL_FAILURE;
348
349 out_Stats.m_bIsDirectory = S_ISDIR(tempStat.st_mode);
350 out_Stats.m_uiFileSize = tempStat.st_size;
351 out_Stats.m_sParentPath = sFileOrFolder;
353 out_Stats.m_sName = plPathUtils::GetFileNameAndExtension(sFileOrFolder); // no OS support, so just pass it through
355
356 return PL_SUCCESS;
357}
358#endif
359
360#if PL_DISABLED(PL_PLATFORM_WINDOWS_UWP)
361
363{
364 if (s_sApplicationPath.IsEmpty())
365 {
366# if PL_ENABLED(PL_PLATFORM_OSX)
367
368 CFBundleRef appBundle = CFBundleGetMainBundle();
369 CFURLRef bundleURL = CFBundleCopyBundleURL(appBundle);
370 CFStringRef bundlePath = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
371
372 if (bundlePath != nullptr)
373 {
374 CFIndex length = CFStringGetLength(bundlePath);
375 CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
376
377 plArrayPtr<char> temp = PL_DEFAULT_NEW_ARRAY(char, static_cast<plUInt32>(maxSize));
378
379 if (CFStringGetCString(bundlePath, temp.GetPtr(), maxSize, kCFStringEncodingUTF8))
380 {
381 s_sApplicationPath = temp.GetPtr();
382 }
383
384 PL_DEFAULT_DELETE_ARRAY(temp);
385 }
386
387 CFRelease(bundlePath);
388 CFRelease(bundleURL);
389 CFRelease(appBundle);
390# elif PL_ENABLED(PL_PLATFORM_ANDROID)
391 {
392 plJniAttachment attachment;
393
394 plJniString packagePath = attachment.GetActivity().Call<plJniString>("getPackageCodePath");
395 // By convention, android requires assets to be placed in the 'Assets' folder
396 // inside the apk thus we use that as our SDK root.
397 plStringBuilder sTemp = packagePath.GetData();
398 sTemp.AppendPath("Assets/plDummyBin");
399 s_sApplicationPath = sTemp;
400 }
401# else
402 char result[PATH_MAX];
403 ssize_t length = readlink("/proc/self/exe", result, PATH_MAX);
404 s_sApplicationPath = plStringView(result, result + length);
405# endif
406 }
407
408 return s_sApplicationPath;
409}
410
412{
413 if (s_sUserDataPath.IsEmpty())
414 {
415# if PL_ENABLED(PL_PLATFORM_ANDROID)
416 android_app* app = plAndroidUtils::GetAndroidApp();
417 s_sUserDataPath = app->activity->internalDataPath;
418# else
419 s_sUserDataPath = getenv("HOME");
420
421 if (s_sUserDataPath.IsEmpty())
422 s_sUserDataPath = getpwuid(getuid())->pw_dir;
423# endif
424 }
425
426 plStringBuilder s = s_sUserDataPath;
427 s.AppendPath(sSubFolder);
428 s.MakeCleanPath();
429 return s;
430}
431
433{
434 if (s_sTempDataPath.IsEmpty())
435 {
436# if PL_ENABLED(PL_PLATFORM_ANDROID)
437 plJniAttachment attachment;
438
439 plJniObject cacheDir = attachment.GetActivity().Call<plJniObject>("getCacheDir");
440 plJniString path = cacheDir.Call<plJniString>("getPath");
441 s_sTempDataPath = path.GetData();
442# else
443 s_sTempDataPath = GetUserDataFolder(".cache").GetData();
444# endif
445 }
446
447 plStringBuilder s = s_sTempDataPath;
448 s.AppendPath(sSubFolder);
449 s.MakeCleanPath();
450 return s;
451}
452
454{
455 if (s_sUserDocumentsPath.IsEmpty())
456 {
457# if PL_ENABLED(PL_PLATFORM_ANDROID)
458 PL_ASSERT_NOT_IMPLEMENTED;
459# else
460 s_sUserDataPath = getenv("HOME");
461
462 if (s_sUserDataPath.IsEmpty())
463 s_sUserDataPath = getpwuid(getuid())->pw_dir;
464# endif
465 }
466
467 plStringBuilder s = s_sUserDocumentsPath;
468 s.AppendPath(sSubFolder);
469 s.MakeCleanPath();
470 return s;
471}
472
474{
475 char tmp[PATH_MAX];
476
477 plStringBuilder clean = getcwd(tmp, PL_ARRAY_SIZE(tmp));
478 clean.MakeCleanPath();
479
480 return clean;
481}
482
483# if PL_ENABLED(PL_SUPPORTS_FILE_ITERATORS)
484
485plFileSystemIterator::plFileSystemIterator() = default;
486
487plFileSystemIterator::~plFileSystemIterator()
488{
489 while (!m_Data.m_Handles.IsEmpty())
490 {
491 closedir((DIR*)m_Data.m_Handles.PeekBack());
492 m_Data.m_Handles.PopBack();
493 }
494}
495
497{
498 return !m_Data.m_Handles.IsEmpty();
499}
500
501namespace
502{
503 plResult UpdateCurrentFile(plFileStats& curFile, const plStringBuilder& curPath, DIR* hSearch, const plString& wildcardSearch)
504 {
505 struct dirent* hCurrentFile = readdir(hSearch);
506 if (hCurrentFile == nullptr)
507 return PL_FAILURE;
508
509 if (!wildcardSearch.IsEmpty())
510 {
511 while (fnmatch(wildcardSearch.GetData(), hCurrentFile->d_name, FNM_NOESCAPE) != 0)
512 {
513 hCurrentFile = readdir(hSearch);
514 if (hCurrentFile == nullptr)
515 return PL_FAILURE;
516 }
517 }
518
519 plStringBuilder absFileName = curPath;
520 absFileName.AppendPath(hCurrentFile->d_name);
521
522 struct stat fileStat = {};
523 stat(absFileName.GetData(), &fileStat);
524
525 curFile.m_uiFileSize = fileStat.st_size;
526 curFile.m_bIsDirectory = hCurrentFile->d_type == DT_DIR;
527 curFile.m_sParentPath = curPath;
528 curFile.m_sName = hCurrentFile->d_name;
530
531 return PL_SUCCESS;
532 }
533} // namespace
534
535void plFileSystemIterator::StartSearch(plStringView sSearchTerm, plBitflags<plFileSystemIteratorFlags> flags /*= plFileSystemIteratorFlags::All*/)
536{
537 PL_ASSERT_DEV(m_Data.m_Handles.IsEmpty(), "Cannot start another search.");
538
539 m_sSearchTerm = sSearchTerm;
540
541 plStringBuilder sSearch = sSearchTerm;
542 sSearch.MakeCleanPath();
543
544 // same as just passing in the folder path, so remove this
545 if (sSearch.EndsWith("/*"))
546 sSearch.Shrink(0, 2);
547
548 // Remove a trailing slash if any
549 sSearch.Trim(nullptr, "/");
550
551 // Since the use of wildcard-ed file names will disable recursion, we ensure both are not used simultaneously.
552 const bool bHasWildcard = sSearch.FindLastSubString("*") || sSearch.FindLastSubString("?");
553 if (flags.IsSet(plFileSystemIteratorFlags::Recursive) == true && bHasWildcard == true)
554 {
555 PL_ASSERT_DEV(false, "Recursive file iteration does not support wildcards. Either don't use recursion, or filter the filenames manually.");
556 return;
557 }
558
559 if (bHasWildcard)
560 {
561 m_Data.m_wildcardSearch = sSearch.GetFileNameAndExtension();
562 m_sCurPath = sSearch.GetFileDirectory();
563 }
564 else
565 {
566 m_Data.m_wildcardSearch.Clear();
567 m_sCurPath = sSearch;
568 }
569
570 PL_ASSERT_DEV(m_sCurPath.IsAbsolutePath(), "The path '{0}' is not absolute.", m_sCurPath);
571
572 m_Flags = flags;
573
574 DIR* hSearch = opendir(m_sCurPath.GetData());
575
576 if (hSearch == nullptr)
577 return;
578
579 if (UpdateCurrentFile(m_CurFile, m_sCurPath, hSearch, m_Data.m_wildcardSearch).Failed())
580 {
581 return;
582 }
583
584 m_Data.m_Handles.PushBack(hSearch);
585
586 if ((m_CurFile.m_sName == "..") || (m_CurFile.m_sName == "."))
587 {
588 Next(); // will search for the next file or folder that is not ".." or "." ; might return false though
589 return;
590 }
591
592 if (m_CurFile.m_bIsDirectory)
593 {
594 if (!m_Flags.IsSet(plFileSystemIteratorFlags::ReportFolders))
595 {
596 Next();
597 return;
598 }
599 }
600 else
601 {
602 if (!m_Flags.IsSet(plFileSystemIteratorFlags::ReportFiles))
603 {
604 Next();
605 return;
606 }
607 }
608}
609
610plInt32 plFileSystemIterator::InternalNext()
611{
612 constexpr plInt32 CallInternalNext = 2;
613
614 if (m_Data.m_Handles.IsEmpty())
615 return PL_FAILURE;
616
617 if (m_Flags.IsSet(plFileSystemIteratorFlags::Recursive) && m_CurFile.m_bIsDirectory && (m_CurFile.m_sName != "..") && (m_CurFile.m_sName != "."))
618 {
619 m_sCurPath.AppendPath(m_CurFile.m_sName.GetData());
620
621 DIR* hSearch = opendir(m_sCurPath.GetData());
622
623 if (hSearch != nullptr && UpdateCurrentFile(m_CurFile, m_sCurPath, hSearch, m_Data.m_wildcardSearch).Succeeded())
624 {
625 m_Data.m_Handles.PushBack(hSearch);
626
627 if ((m_CurFile.m_sName == "..") || (m_CurFile.m_sName == "."))
628 return CallInternalNext; // will search for the next file or folder that is not ".." or "." ; might return false though
629
630 if (m_CurFile.m_bIsDirectory)
631 {
632 if (!m_Flags.IsSet(plFileSystemIteratorFlags::ReportFolders))
633 return CallInternalNext;
634 }
635 else
636 {
637 if (!m_Flags.IsSet(plFileSystemIteratorFlags::ReportFiles))
638 return CallInternalNext;
639 }
640
641 return PL_SUCCESS;
642 }
643
644 // if the recursion did not work, just iterate in this folder further
645 }
646
647 if (UpdateCurrentFile(m_CurFile, m_sCurPath, (DIR*)m_Data.m_Handles.PeekBack(), m_Data.m_wildcardSearch).Failed())
648 {
649 // nothing found in this directory anymore
650 closedir((DIR*)m_Data.m_Handles.PeekBack());
651 m_Data.m_Handles.PopBack();
652
653 if (m_Data.m_Handles.IsEmpty())
654 return PL_FAILURE;
655
656 m_sCurPath.PathParentDirectory();
657 if (m_sCurPath.GetElementCount() > 1 && m_sCurPath.EndsWith("/"))
658 {
659 m_sCurPath.Shrink(0, 1);
660 }
661
662 return CallInternalNext;
663 }
664
665 if ((m_CurFile.m_sName == "..") || (m_CurFile.m_sName == "."))
666 return CallInternalNext;
667
668 if (m_CurFile.m_bIsDirectory)
669 {
670 if (!m_Flags.IsSet(plFileSystemIteratorFlags::ReportFolders))
671 return CallInternalNext;
672 }
673 else
674 {
675 if (!m_Flags.IsSet(plFileSystemIteratorFlags::ReportFiles))
676 return CallInternalNext;
677 }
678
679 return PL_SUCCESS;
680}
681
682# endif
683
684#endif // PL_DISABLED(PL_PLATFORM_WINDOWS_UWP)
This class encapsulates an array and it's size. It is recommended to use this class instead of plain ...
Definition ArrayPtr.h:37
PL_ALWAYS_INLINE PointerType GetPtr() const
Returns the pointer to the array.
Definition ArrayPtr.h:118
bool IsValid() const
Returns true if the iterator currently points to a valid file entry.
void StartSearch(plStringView sSearchTerm, plBitflags< plFileSystemIteratorFlags > flags=plFileSystemIteratorFlags::Default)
Starts a search at the given folder. Use * and ? as wildcards.
void Next()
Advances the iterator to the next file object. Might recurse into sub-folders.
static void Error(plLogInterface *pInterface, const plFormatString &string)
An error that needs to be fixed as soon as possible.
Definition Log.cpp:375
static T * AddByteOffset(T *pPtr, std::ptrdiff_t offset)
Returns the address stored in ptr plus the given byte offset iOffset, cast to type T.
static plStringView GetApplicationPath()
Returns the full path to the application binary.
static plString GetUserDocumentsFolder(plStringView sSubFolder={})
Returns the folder into which the user may want to store documents. Append a sub-folder for your appl...
static plString GetTempDataFolder(plStringView sSubFolder={})
Returns the folder into which temp data may be written.
static const plString GetCurrentWorkingDirectory()
Returns the processes current working directory (CWD).
static plString GetUserDataFolder(plStringView sSubFolder={})
Returns the folder into which user data may be safely written. Append a sub-folder for your applicati...
static plStringView GetFileNameAndExtension(plStringView sPath)
Returns the substring that represents the file name including the file extension.
Definition PathUtils.cpp:85
plStringBuilder is a class that is meant for creating and modifying strings.
Definition StringBuilder.h:35
const char * GetData() const
Returns a char pointer to the internal Utf8 data.
Definition StringBuilder_inl.h:148
plUInt32 GetElementCount() const
Returns the number of bytes that this string takes up.
Definition StringBuilder_inl.h:78
void PathParentDirectory(plUInt32 uiLevelsUp=1)
Modifies this string to point to the parent directory.
Definition StringBuilder.cpp:856
void Shrink(plUInt32 uiShrinkCharsFront, plUInt32 uiShrinkCharsBack)
Removes the first n and last m characters from this string.
Definition StringBuilder.cpp:393
void MakeCleanPath()
Removes "../" where possible, replaces all path separators with /, removes double slashes.
Definition StringBuilder.cpp:751
void Trim(const char *szTrimChars=" \f\n\r\t\v")
Removes all characters from the start and end that appear in the given strings.
Definition StringBuilder.cpp:1179
void AppendPath(plStringView sPath1, plStringView sPath2={}, plStringView sPath3={}, plStringView sPath4={})
Appends several path pieces. Makes sure they are always properly separated by a slash.
Definition StringBuilder.cpp:866
static plUInt32 GetCharacterCount(const char *szUtf8, const char *pStringEnd=plUnicodeUtils::GetMaxStringEnd< char >())
Returns the number of characters (not Bytes!) in a Utf8 string (excluding the zero terminator),...
Definition StringUtils_inl.h:81
plStringView represent a read-only sub-string of a larger string, as it can store a dedicated string ...
Definition StringView.h:34
const char * GetEndPointer() const
Returns the end of the view range. This will point to the byte AFTER the last character.
Definition StringView.h:108
const char * GetStartPointer() const
Returns the start of the view range.
Definition StringView.h:102
static void Sleep(const plTime &duration)
Suspends the execution of the current thread for the given amount of time. (Precision may vary accord...
Definition ThreadUtils_Posix.h:29
static plTimestamp MakeFromInt(plInt64 iTimeValue, plSIUnitOfTime::Enum unitOfTime)
Returns a timestamp initialized from 'iTimeValue' in 'unitOfTime' since Unix epoch.
Definition Timestamp.cpp:36
The plBitflags class allows you to work with type-safe bitflags.
Definition Bitflags.h:82
PL_ALWAYS_INLINE bool IsSet(Enum flag) const
Checks if certain flags are set within the bitfield.
Definition Bitflags.h:127
Enum
Definition OSFile.h:24
@ Append
Open file for appending (writing, but always only at the end, already existing data is preserved).
Definition OSFile.h:28
@ Write
Open file for writing (already existing data is discarded).
Definition OSFile.h:27
@ Read
Open file for reading.
Definition OSFile.h:26
Enum
Definition FileEnums.h:18
@ FromStart
The seek position is relative to the file's beginning.
Definition FileEnums.h:19
@ FromCurrent
The seek position is relative to the file's current seek position.
Definition FileEnums.h:21
@ FromEnd
The seek position is relative to the file's end.
Definition FileEnums.h:20
Enum
Definition FileEnums.h:7
@ Exclusive
No other process is allowed to access the file for reading or writing, while it is open.
Definition FileEnums.h:9
@ Default
Results in 'Exclusive' when requesting write access and 'SharedReads' when requesting read access....
Definition FileEnums.h:8
@ SharedReads
Other processes may read the file concurrently.
Definition FileEnums.h:10
Holds the stats for a file.
Definition OSFile.h:34
bool m_bIsDirectory
Whether the file object is a file or folder.
Definition OSFile.h:56
plString m_sName
The name of the file or folder that the stats are for. Does not include the parent path to it....
Definition OSFile.h:47
plUInt64 m_uiFileSize
The size of the file in bytes.
Definition OSFile.h:53
plStringBuilder m_sParentPath
Path to the parent folder. Append m_sName to m_sParentPath to obtain the full path.
Definition OSFile.h:43
plTimestamp m_LastModificationTime
The last modification time as an UTC timestamp since Unix epoch.
Definition OSFile.h:50
const char * GetData() const
Returns a pointer to the internal Utf8 string.
Definition String_inl.h:56
Default enum for returning failure or success, instead of using a bool.
Definition Types.h:54
@ Second
SI-unit of time (base unit)
Definition Timestamp.h:13
bool IsAbsolutePath() const
Returns true, if the given path represents an absolute path on the current OS.
Definition StringBase_inl.h:360
const char * FindLastSubString(plStringView sStringToFind, const char *szStartSearchAt=nullptr) const
Definition StringBase_inl.h:77
plStringView GetFileNameAndExtension() const
Returns the substring that represents the file name including the file extension.
Definition StringBase_inl.h:372
bool IsEmpty() const
Returns whether the string is an empty string.
Definition StringBase_inl.h:25
bool EndsWith(plStringView sEndsWith) const
Returns true, if this string ends with the given string.
Definition StringBase_inl.h:43
plStringView GetFileDirectory() const
Returns the directory of the given file, which is the substring up to the last path separator.
Definition StringBase_inl.h:366
The time class encapsulates a double value storing the time in seconds.
Definition Time.h:12
PL_ALWAYS_INLINE static constexpr plTime MakeFromMilliseconds(double fMilliseconds)
Creates an instance of plTime that was initialized from milliseconds.
Definition Time.h:26