Files
GacUI/Import/VlppOS.Linux.cpp
2025-09-22 06:23:15 -07:00

1265 lines
28 KiB
C++

/***********************************************************************
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
DEVELOPER: Zihan Chen(vczh)
***********************************************************************/
#include "VlppOS.h"
#include "Vlpp.h"
/***********************************************************************
.\FILESYSTEM.LINUX.CPP
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#ifndef VCZH_GCC
static_assert(false, "Do not build this file for Windows applications.");
#endif
namespace vl
{
namespace stream
{
extern Ptr<IFileStreamImpl> CreateOSFileStreamImpl(const WString& fileName, FileStream::AccessRight accessRight);
}
namespace filesystem
{
using namespace collections;
using namespace stream;
/***********************************************************************
LinuxFileSystemImpl
***********************************************************************/
class LinuxFileSystemImpl : public feature_injection::FeatureImpl<IFileSystemImpl>
{
public:
// FilePath operations implementation
void Initialize(WString& fullPath) const override
{
{
Array<wchar_t> buffer(fullPath.Length() + 1);
wcscpy(&buffer[0], fullPath.Buffer());
FilePath::NormalizeDelimiters(buffer);
fullPath = &buffer[0];
}
if (fullPath.Length() == 0)
fullPath = WString::Unmanaged(L"/");
if (fullPath[0] != FilePath::Delimiter)
{
char buffer[PATH_MAX] = { 0 };
getcwd(buffer, PATH_MAX);
fullPath = atow(AString(buffer)) + WString::FromChar(FilePath::Delimiter) + fullPath;
}
{
collections::List<WString> components;
FilePath::GetPathComponents(fullPath, components);
for (int i = 0; i < components.Count(); i++)
{
if (components[i] == L".")
{
components.RemoveAt(i);
i--;
}
else if (components[i] == L"..")
{
if (i > 0)
{
components.RemoveAt(i);
components.RemoveAt(i - 1);
i -= 2;
}
else
{
throw ArgumentException(L"Illegal path.");
}
}
}
fullPath = FilePath::ComponentsToPath(components);
}
FilePath::TrimLastDelimiter(fullPath);
}
bool IsFile(const WString& fullPath) const override
{
struct stat info;
AString path = wtoa(fullPath);
int result = stat(path.Buffer(), &info);
if(result != 0) return false;
else return S_ISREG(info.st_mode);
}
bool IsFolder(const WString& fullPath) const override
{
struct stat info;
AString path = wtoa(fullPath);
int result = stat(path.Buffer(), &info);
if(result != 0) return false;
else return S_ISDIR(info.st_mode);
}
bool IsRoot(const WString& fullPath) const override
{
return fullPath == L"/";
}
WString GetRelativePathFor(const WString& fromPath, const WString& toPath) const override
{
if (fromPath.Length() == 0 || toPath.Length() == 0 || fromPath[0] != toPath[0])
{
return toPath;
}
collections::List<WString> srcComponents, tgtComponents, resultComponents;
FilePath::GetPathComponents(IsFolder(fromPath) ? fromPath : FilePath(fromPath).GetFolder().GetFullPath(), srcComponents);
FilePath::GetPathComponents(toPath, tgtComponents);
int minLength = srcComponents.Count() <= tgtComponents.Count() ? srcComponents.Count() : tgtComponents.Count();
int lastCommonComponent = 0;
for (int i = 0; i < minLength; i++)
{
if (srcComponents[i] == tgtComponents[i])
{
lastCommonComponent = i;
}
else
break;
}
for (int i = lastCommonComponent + 1; i < srcComponents.Count(); i++)
{
resultComponents.Add(L"..");
}
for (int i = lastCommonComponent + 1; i < tgtComponents.Count(); i++)
{
resultComponents.Add(tgtComponents[i]);
}
return FilePath::ComponentsToPath(resultComponents);
}
// File operations implementation
bool FileDelete(const FilePath& filePath) const override
{
AString path = wtoa(filePath.GetFullPath());
return unlink(path.Buffer()) == 0;
}
bool FileRename(const FilePath& filePath, const WString& newName) const override
{
AString oldFileName = wtoa(filePath.GetFullPath());
AString newFileName = wtoa((filePath.GetFolder() / newName).GetFullPath());
return rename(oldFileName.Buffer(), newFileName.Buffer()) == 0;
}
// Folder operations implementation
bool GetFolders(const FilePath& folderPath, collections::List<Folder>& folders) const override
{
DIR *dir;
AString searchPath = wtoa(folderPath.GetFullPath());
if ((dir = opendir(searchPath.Buffer())) == NULL)
{
return false;
}
struct dirent* entry;
while ((entry = readdir(dir)) != NULL)
{
WString childName = atow(AString(entry->d_name));
FilePath childFullPath = folderPath / childName;
if (childName != L"." && childName != L".." && childFullPath.IsFolder())
{
folders.Add(Folder(childFullPath));
}
}
if (closedir(dir) != 0)
{
return false;
}
return true;
}
bool GetFiles(const FilePath& folderPath, collections::List<File>& files) const override
{
DIR* dir;
AString searchPath = wtoa(folderPath.GetFullPath());
if ((dir = opendir(searchPath.Buffer())) == NULL)
{
return false;
}
struct dirent* entry;
while ((entry = readdir(dir)) != NULL)
{
FilePath childFullPath = folderPath / (atow(AString(entry->d_name)));
if (childFullPath.IsFile())
{
files.Add(File(childFullPath));
}
}
if (closedir(dir) != 0)
{
return false;
}
return true;
}
bool CreateFolder(const FilePath& folderPath) const override
{
AString path = wtoa(folderPath.GetFullPath());
return mkdir(path.Buffer(), 0777) == 0;
}
bool DeleteFolder(const FilePath& folderPath) const override
{
AString path = wtoa(folderPath.GetFullPath());
return rmdir(path.Buffer()) == 0;
}
bool FolderRename(const FilePath& folderPath, const WString& newName) const override
{
AString oldFileName = wtoa(folderPath.GetFullPath());
AString newFileName = wtoa((folderPath.GetFolder() / newName).GetFullPath());
return rename(oldFileName.Buffer(), newFileName.Buffer()) == 0;
}
Ptr<stream::IFileStreamImpl> GetFileStreamImpl(const WString& fileName, stream::FileStream::AccessRight accessRight) const override
{
return stream::CreateOSFileStreamImpl(fileName, accessRight);
}
};
/***********************************************************************
Global FileSystem Implementation
***********************************************************************/
IFileSystemImpl* GetOSFileSystemImpl()
{
static LinuxFileSystemImpl osFileSystemImpl;
return &osFileSystemImpl;
}
}
}
/***********************************************************************
.\LOCALE.LINUX.CPP
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_GCC
static_assert(false, "Do not build this file for Windows applications.");
#endif
namespace vl
{
ILocaleImpl* GetOSLocaleImpl()
{
static EnUsLocaleImpl linuxLocaleImpl;
return &linuxLocaleImpl;
}
}
/***********************************************************************
.\THREADING.LINUX.CPP
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#include <pthread.h>
#include <fcntl.h>
#include <semaphore.h>
#include <errno.h>
#if defined(__APPLE__) || defined(__APPLE_CC__)
#include <CoreFoundation/CoreFoundation.h>
#endif
#ifndef VCZH_GCC
static_assert(false, "Do not build this file for Windows applications.");
#endif
namespace vl
{
using namespace threading_internal;
using namespace collections;
/***********************************************************************
Thread
***********************************************************************/
namespace threading_internal
{
struct ThreadData
{
pthread_t id;
EventObject ev;
};
class ProceduredThread : public Thread
{
private:
Thread::ThreadProcedure procedure;
void* argument;
bool deleteAfterStopped;
protected:
void Run()
{
bool deleteAfterStopped = this->deleteAfterStopped;
ThreadLocalStorage::FixStorages();
try
{
procedure(this, argument);
threadState=Thread::Stopped;
internalData->ev.Signal();
ThreadLocalStorage::ClearStorages();
}
catch (...)
{
ThreadLocalStorage::ClearStorages();
throw;
}
if(deleteAfterStopped)
{
delete this;
}
}
public:
ProceduredThread(Thread::ThreadProcedure _procedure, void* _argument, bool _deleteAfterStopped)
:procedure(_procedure)
,argument(_argument)
,deleteAfterStopped(_deleteAfterStopped)
{
}
};
class LambdaThread : public Thread
{
private:
Func<void()> procedure;
bool deleteAfterStopped;
protected:
void Run()
{
bool deleteAfterStopped = this->deleteAfterStopped;
ThreadLocalStorage::FixStorages();
try
{
procedure();
threadState=Thread::Stopped;
internalData->ev.Signal();
ThreadLocalStorage::ClearStorages();
}
catch (...)
{
ThreadLocalStorage::ClearStorages();
throw;
}
if(deleteAfterStopped)
{
delete this;
}
}
public:
LambdaThread(const Func<void()>& _procedure, bool _deleteAfterStopped)
:procedure(_procedure)
,deleteAfterStopped(_deleteAfterStopped)
{
}
};
}
void InternalThreadProc(Thread* thread)
{
thread->Run();
}
void* InternalThreadProcWrapper(void* lpParameter)
{
InternalThreadProc((Thread*)lpParameter);
return 0;
}
Thread::Thread()
{
internalData=new ThreadData;
internalData->ev.CreateManualUnsignal(false);
threadState=Thread::NotStarted;
}
Thread::~Thread()
{
if (internalData)
{
Stop();
if (threadState!=Thread::NotStarted)
{
pthread_detach(internalData->id);
}
delete internalData;
}
}
Thread* Thread::CreateAndStart(ThreadProcedure procedure, void* argument, bool deleteAfterStopped)
{
if(procedure)
{
Thread* thread=new ProceduredThread(procedure, argument, deleteAfterStopped);
if(thread->Start())
{
return thread;
}
else
{
delete thread;
}
}
return 0;
}
Thread* Thread::CreateAndStart(const Func<void()>& procedure, bool deleteAfterStopped)
{
Thread* thread=new LambdaThread(procedure, deleteAfterStopped);
if(thread->Start())
{
return thread;
}
else
{
delete thread;
}
return 0;
}
void Thread::Sleep(vint ms)
{
if (ms >= 1000)
{
sleep(ms / 1000);
}
if (ms % 1000)
{
usleep((ms % 1000) * 1000);
}
}
vint Thread::GetCPUCount()
{
return (vint)sysconf(_SC_NPROCESSORS_ONLN);
}
vint Thread::GetCurrentThreadId()
{
return (vint)::pthread_self();
}
bool Thread::Start()
{
if(threadState==Thread::NotStarted)
{
if(pthread_create(&internalData->id, nullptr, &InternalThreadProcWrapper, this)==0)
{
threadState=Thread::Running;
return true;
}
}
return false;
}
bool Thread::Wait()
{
return internalData->ev.Wait();
}
bool Thread::Stop()
{
if (threadState==Thread::Running)
{
if(pthread_cancel(internalData->id)==0)
{
threadState=Thread::Stopped;
internalData->ev.Signal();
return true;
}
}
return false;
}
Thread::ThreadState Thread::GetState()
{
return threadState;
}
/***********************************************************************
Mutex
***********************************************************************/
namespace threading_internal
{
struct MutexData
{
Semaphore sem;
};
};
Mutex::Mutex()
{
internalData = new MutexData;
}
Mutex::~Mutex()
{
delete internalData;
}
bool Mutex::Create(bool owned, const WString& name)
{
return internalData->sem.Create(owned ? 0 : 1, 1, name);
}
bool Mutex::Open(bool inheritable, const WString& name)
{
return internalData->sem.Open(inheritable, name);
}
bool Mutex::Release()
{
return internalData->sem.Release();
}
bool Mutex::Wait()
{
return internalData->sem.Wait();
}
/***********************************************************************
Semaphore
***********************************************************************/
namespace threading_internal
{
struct SemaphoreData
{
sem_t semUnnamed;
sem_t* semNamed = nullptr;
};
}
Semaphore::Semaphore()
:internalData(0)
{
}
Semaphore::~Semaphore()
{
if (internalData)
{
if (internalData->semNamed)
{
sem_close(internalData->semNamed);
}
else
{
sem_destroy(&internalData->semUnnamed);
}
delete internalData;
}
}
bool Semaphore::Create(vint initialCount, vint maxCount, const WString& name)
{
if (internalData) return false;
if (initialCount > maxCount) return false;
internalData = new SemaphoreData;
#if defined(__APPLE__)
AString auuid;
if(name.Length() == 0)
{
CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault);
CFStringRef cfstr = CFUUIDCreateString(kCFAllocatorDefault, cfuuid);
auuid = CFStringGetCStringPtr(cfstr, kCFStringEncodingASCII);
CFRelease(cfstr);
CFRelease(cfuuid);
}
auuid = auuid.Insert(0, "/");
// OSX SEM_NAME_LENGTH = 31
if(auuid.Length() >= 30)
auuid = auuid.Sub(0, 30);
if ((internalData->semNamed = sem_open(auuid.Buffer(), O_CREAT, O_RDWR, initialCount)) == SEM_FAILED)
{
delete internalData;
internalData = 0;
return false;
}
#else
if (name == L"")
{
if(sem_init(&internalData->semUnnamed, 0, (int)initialCount) == -1)
{
delete internalData;
internalData = 0;
return false;
}
}
else
{
AString astr = wtoa(name);
if ((internalData->semNamed = sem_open(astr.Buffer(), O_CREAT, 0777, initialCount)) == SEM_FAILED)
{
delete internalData;
internalData = 0;
return false;
}
}
#endif
Release(initialCount);
return true;
}
bool Semaphore::Open(bool inheritable, const WString& name)
{
if (internalData) return false;
if (inheritable) return false;
internalData = new SemaphoreData;
if (!(internalData->semNamed = sem_open(wtoa(name).Buffer(), 0)))
{
delete internalData;
internalData = 0;
return false;
}
return true;
}
bool Semaphore::Release()
{
return Release(1);
}
vint Semaphore::Release(vint count)
{
for (vint i = 0; i < count; i++)
{
if (internalData->semNamed)
{
sem_post(internalData->semNamed);
}
else
{
sem_post(&internalData->semUnnamed);
}
}
return true;
}
bool Semaphore::Wait()
{
if (internalData->semNamed)
{
return sem_wait(internalData->semNamed) == 0;
}
else
{
return sem_wait(&internalData->semUnnamed) == 0;
}
}
/***********************************************************************
EventObject
***********************************************************************/
namespace threading_internal
{
struct EventData
{
bool autoReset;
volatile bool signaled;
CriticalSection mutex;
ConditionVariable cond;
atomic_vint counter = 0;
};
}
EventObject::EventObject()
{
internalData = nullptr;
}
EventObject::~EventObject()
{
if (internalData)
{
delete internalData;
}
}
bool EventObject::CreateAutoUnsignal(bool signaled, const WString& name)
{
if (name!=L"") return false;
if (internalData) return false;
internalData = new EventData;
internalData->autoReset = true;
internalData->signaled = signaled;
return true;
}
bool EventObject::CreateManualUnsignal(bool signaled, const WString& name)
{
if (name!=L"") return false;
if (internalData) return false;
internalData = new EventData;
internalData->autoReset = false;
internalData->signaled = signaled;
return true;
}
bool EventObject::Signal()
{
if (!internalData) return false;
internalData->mutex.Enter();
internalData->signaled = true;
if (internalData->counter)
{
if (internalData->autoReset)
{
internalData->cond.WakeOnePending();
internalData->signaled = false;
}
else
{
internalData->cond.WakeAllPendings();
}
}
internalData->mutex.Leave();
return true;
}
bool EventObject::Unsignal()
{
if (!internalData) return false;
internalData->mutex.Enter();
internalData->signaled = false;
internalData->mutex.Leave();
return true;
}
bool EventObject::Wait()
{
if (!internalData) return false;
internalData->mutex.Enter();
if (internalData->signaled)
{
if (internalData->autoReset)
{
internalData->signaled = false;
}
}
else
{
INCRC(&internalData->counter);
internalData->cond.SleepWith(internalData->mutex);
DECRC(&internalData->counter);
}
internalData->mutex.Leave();
return true;
}
/***********************************************************************
ThreadPoolLite
***********************************************************************/
namespace threading_internal
{
struct ThreadPoolTask
{
Func<void()> task;
Ptr<ThreadPoolTask> next;
};
struct ThreadPoolData
{
Semaphore semaphore;
EventObject taskFinishEvent;
Ptr<ThreadPoolTask> taskBegin;
Ptr<ThreadPoolTask>* taskEnd = nullptr;
volatile bool stopping = false;
List<Thread*> taskThreads;
};
SpinLock threadPoolLock;
ThreadPoolData* threadPoolData = nullptr;
void ThreadPoolProc(Thread* thread, void* argument)
{
while (true)
{
Ptr<ThreadPoolTask> task;
threadPoolData->semaphore.Wait();
SPIN_LOCK(threadPoolLock)
{
if (threadPoolData->taskBegin)
{
task = threadPoolData->taskBegin;
threadPoolData->taskBegin = task->next;
}
if (!threadPoolData->taskBegin)
{
threadPoolData->taskEnd = &threadPoolData->taskBegin;
threadPoolData->taskFinishEvent.Signal();
}
}
if (task)
{
ThreadLocalStorage::FixStorages();
try
{
task->task();
ThreadLocalStorage::ClearStorages();
}
catch (...)
{
ThreadLocalStorage::ClearStorages();
}
}
else if (threadPoolData->stopping)
{
return;
}
}
}
bool ThreadPoolQueue(const Func<void()>& proc)
{
SPIN_LOCK(threadPoolLock)
{
if (!threadPoolData)
{
threadPoolData = new ThreadPoolData;
threadPoolData->semaphore.Create(0, 65536);
threadPoolData->taskFinishEvent.CreateManualUnsignal(false);
threadPoolData->taskEnd = &threadPoolData->taskBegin;
for (vint i = 0; i < Thread::GetCPUCount() * 4; i++)
{
threadPoolData->taskThreads.Add(Thread::CreateAndStart(&ThreadPoolProc, nullptr, false));
}
}
if (threadPoolData)
{
if (threadPoolData->stopping)
{
return false;
}
auto task = Ptr(new ThreadPoolTask);
task->task = proc;
*threadPoolData->taskEnd = task;
threadPoolData->taskEnd = &task->next;
threadPoolData->semaphore.Release();
threadPoolData->taskFinishEvent.Unsignal();
}
}
return true;
}
bool ThreadPoolStop(bool discardPendingTasks)
{
SPIN_LOCK(threadPoolLock)
{
if (!threadPoolData) return false;
if (threadPoolData->stopping) return false;
threadPoolData->stopping = true;
if (discardPendingTasks)
{
threadPoolData->taskEnd = &threadPoolData->taskBegin;
threadPoolData->taskBegin = nullptr;
}
threadPoolData->semaphore.Release(threadPoolData->taskThreads.Count());
}
threadPoolData->taskFinishEvent.Wait();
// TODO: (enumerable) foreach
for (vint i = 0; i < threadPoolData->taskThreads.Count(); i++)
{
auto thread = threadPoolData->taskThreads[i];
thread->Wait();
delete thread;
}
threadPoolData->taskThreads.Clear();
SPIN_LOCK(threadPoolLock)
{
delete threadPoolData;
threadPoolData = nullptr;
}
return true;
}
}
ThreadPoolLite::ThreadPoolLite()
{
}
ThreadPoolLite::~ThreadPoolLite()
{
}
bool ThreadPoolLite::Queue(void(*proc)(void*), void* argument)
{
return ThreadPoolQueue([proc, argument](){proc(argument);});
}
bool ThreadPoolLite::Queue(const Func<void()>& proc)
{
return ThreadPoolQueue(proc);
}
bool ThreadPoolLite::Stop(bool discardPendingTasks)
{
return ThreadPoolStop(discardPendingTasks);
}
/***********************************************************************
CriticalSection
***********************************************************************/
namespace threading_internal
{
struct CriticalSectionData
{
pthread_mutex_t mutex;
};
}
CriticalSection::CriticalSection()
{
internalData = new CriticalSectionData;
pthread_mutex_init(&internalData->mutex, nullptr);
}
CriticalSection::~CriticalSection()
{
pthread_mutex_destroy(&internalData->mutex);
delete internalData;
}
bool CriticalSection::TryEnter()
{
return pthread_mutex_trylock(&internalData->mutex) == 0;
}
void CriticalSection::Enter()
{
pthread_mutex_lock(&internalData->mutex);
}
void CriticalSection::Leave()
{
pthread_mutex_unlock(&internalData->mutex);
}
CriticalSection::Scope::Scope(CriticalSection& _criticalSection)
:criticalSection(&_criticalSection)
{
criticalSection->Enter();
}
CriticalSection::Scope::~Scope()
{
criticalSection->Leave();
}
/***********************************************************************
ReaderWriterLock
***********************************************************************/
namespace threading_internal
{
struct ReaderWriterLockData
{
pthread_rwlock_t rwlock;
};
}
ReaderWriterLock::ReaderWriterLock()
{
internalData = new ReaderWriterLockData;
pthread_rwlock_init(&internalData->rwlock, nullptr);
}
ReaderWriterLock::~ReaderWriterLock()
{
pthread_rwlock_destroy(&internalData->rwlock);
delete internalData;
}
bool ReaderWriterLock::TryEnterReader()
{
return pthread_rwlock_tryrdlock(&internalData->rwlock) == 0;
}
void ReaderWriterLock::EnterReader()
{
pthread_rwlock_rdlock(&internalData->rwlock);
}
void ReaderWriterLock::LeaveReader()
{
pthread_rwlock_unlock(&internalData->rwlock);
}
bool ReaderWriterLock::TryEnterWriter()
{
return pthread_rwlock_trywrlock(&internalData->rwlock) == 0;
}
void ReaderWriterLock::EnterWriter()
{
pthread_rwlock_wrlock(&internalData->rwlock);
}
void ReaderWriterLock::LeaveWriter()
{
pthread_rwlock_unlock(&internalData->rwlock);
}
ReaderWriterLock::ReaderScope::ReaderScope(ReaderWriterLock& _lock)
:lock(&_lock)
{
lock->EnterReader();
}
ReaderWriterLock::ReaderScope::~ReaderScope()
{
lock->LeaveReader();
}
ReaderWriterLock::WriterScope::WriterScope(ReaderWriterLock& _lock)
:lock(&_lock)
{
lock->EnterWriter();
}
ReaderWriterLock::WriterScope::~WriterScope()
{
lock->LeaveReader();
}
/***********************************************************************
ConditionVariable
***********************************************************************/
namespace threading_internal
{
struct ConditionVariableData
{
pthread_cond_t cond;
};
}
ConditionVariable::ConditionVariable()
{
internalData = new ConditionVariableData;
pthread_cond_init(&internalData->cond, nullptr);
}
ConditionVariable::~ConditionVariable()
{
pthread_cond_destroy(&internalData->cond);
delete internalData;
}
bool ConditionVariable::SleepWith(CriticalSection& cs)
{
return pthread_cond_wait(&internalData->cond, &cs.internalData->mutex) == 0;
}
void ConditionVariable::WakeOnePending()
{
pthread_cond_signal(&internalData->cond);
}
void ConditionVariable::WakeAllPendings()
{
pthread_cond_broadcast(&internalData->cond);
}
/***********************************************************************
ThreadLocalStorage
***********************************************************************/
#define KEY ((pthread_key_t&)key)
ThreadLocalStorage::ThreadLocalStorage(Destructor _destructor)
:destructor(_destructor)
{
static_assert(sizeof(key) >= sizeof(pthread_key_t), "ThreadLocalStorage's key storage is not large enouth.");
PushStorage(this);
auto error = pthread_key_create(&KEY, destructor);
CHECK_ERROR(error != EAGAIN && error != ENOMEM, L"vl::ThreadLocalStorage::ThreadLocalStorage()#Failed to create a thread local storage index.");
}
ThreadLocalStorage::~ThreadLocalStorage()
{
pthread_key_delete(KEY);
}
void* ThreadLocalStorage::Get()
{
CHECK_ERROR(!disposed, L"vl::ThreadLocalStorage::Get()#Cannot access a disposed ThreadLocalStorage.");
return pthread_getspecific(KEY);
}
void ThreadLocalStorage::Set(void* data)
{
CHECK_ERROR(!disposed, L"vl::ThreadLocalStorage::Set()#Cannot access a disposed ThreadLocalStorage.");
pthread_setspecific(KEY, data);
}
#undef KEY
}
/***********************************************************************
.\ENCODING\CHARFORMAT\CHARFORMAT.LINUX.CPP
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#include <string.h>
#ifndef VCZH_GCC
static_assert(false, "Do not build this file for Windows applications.");
#endif
namespace vl
{
namespace stream
{
using namespace vl::encoding;
bool IsMbcsLeadByte(char c)
{
return (vint8_t)c < 0;
}
void MbcsToWChar(wchar_t* wideBuffer, vint wideChars, vint wideReaded, char* mbcsBuffer, vint mbcsChars)
{
AString a = AString::CopyFrom(mbcsBuffer, mbcsChars);
WString w = atow(a);
memcpy(wideBuffer, w.Buffer(), wideReaded * sizeof(wchar_t));
}
/***********************************************************************
MbcsEncoder
***********************************************************************/
vint MbcsEncoder::WriteString(wchar_t* _buffer, vint chars)
{
WString w = WString::CopyFrom(_buffer, chars);
AString a = wtoa(w);
vint length = a.Length();
vint result = stream->Write((void*)a.Buffer(), length);
if (result != length)
{
Close();
return 0;
}
return chars;
}
/***********************************************************************
Helper Functions
***********************************************************************/
extern bool CanBeMbcs(unsigned char* buffer, vint size);
extern bool CanBeUtf8(unsigned char* buffer, vint size);
extern bool CanBeUtf16(unsigned char* buffer, vint size, bool& hitSurrogatePairs);
extern bool CanBeUtf16BE(unsigned char* buffer, vint size, bool& hitSurrogatePairs);
/***********************************************************************
TestEncoding
***********************************************************************/
extern void TestEncodingInternal(
unsigned char* buffer,
vint size,
BomEncoder::Encoding& encoding,
bool containsBom,
bool utf16HitSurrogatePairs,
bool utf16BEHitSurrogatePairs,
bool roughMbcs,
bool roughUtf8,
bool roughUtf16,
bool roughUtf16BE
)
{
if (roughUtf16 && roughUtf16BE && !roughUtf8)
{
if (utf16BEHitSurrogatePairs && !utf16HitSurrogatePairs)
{
encoding = BomEncoder::Utf16BE;
}
else
{
encoding = BomEncoder::Utf16;
}
}
else
{
encoding = BomEncoder::Utf8;
}
}
}
}