commit x64 compilation from lulu cause the other branch dont seems to compile properly at home
This commit is contained in:
281
include/platform/alloc/ialloc.cpp
Normal file
281
include/platform/alloc/ialloc.cpp
Normal file
@ -0,0 +1,281 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "alloc/ialloc.h"
|
||||
#include "thread/mutex.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS::Alloc;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void *DefaultAllocator::Alloc(size_t size, System sys)
|
||||
{ __NSTAT_WRAPALLOC(malloc(size), sys) }
|
||||
void DefaultAllocator::Delete(void *addr, System sys)
|
||||
{ __NSTAT_WRAPDELETE(free(addr), sys) }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#if __ENABLE_ALLOCATION_STAT__
|
||||
|
||||
namespace GS {
|
||||
namespace Alloc {
|
||||
|
||||
Stat system_stat[SystemCount];
|
||||
SystemDesc system_desc[SystemCount] =
|
||||
{
|
||||
{ "General", "System" },
|
||||
|
||||
{ "Container", "List Item" },
|
||||
{ "String", "String Buffer" },
|
||||
|
||||
{ "I/O", "Filesystem" },
|
||||
{ "I/O", "Metatag" },
|
||||
|
||||
{ "Animation", "Curve" },
|
||||
{ "Animation", "Motion" },
|
||||
{ "Animation", "Animation Source" },
|
||||
|
||||
{ "Maths", "Vector" },
|
||||
{ "Maths", "Matrix" },
|
||||
|
||||
{ "Physics", "Physics" },
|
||||
|
||||
{ "Scene 3D", "Item" },
|
||||
|
||||
{ "Resource", "Geometry" },
|
||||
{ "Resource", "Material" },
|
||||
{ "Resource", "Texture" },
|
||||
{ "Resource", "Picture" },
|
||||
|
||||
{ "Mixer", "System" },
|
||||
{ "Resource", "Sound" },
|
||||
|
||||
{ "Renderer", "System" },
|
||||
{ "Renderer", "Render Job" },
|
||||
{ "Renderer", "Terrain" },
|
||||
|
||||
{ "Renderer", "VBO" },
|
||||
|
||||
{ "Global", "Other" }
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
size_t GetAdjustedAllocationSize(size_t size)
|
||||
{ return size + sizeof(Header); }
|
||||
void *SetupAllocationStat(void *addr, size_t size)
|
||||
{
|
||||
Header *h = (Header *)addr;
|
||||
h->size = size;
|
||||
return (void *)(h + 1);
|
||||
}
|
||||
void *GetAllocationStat(void *addr, Header *&h)
|
||||
{
|
||||
h = ((Header *)addr) - 1;
|
||||
return (void *)h;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static Mutex stat_mutex;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void UpdateStatAlloc(size_t size, System system)
|
||||
{
|
||||
MutexLock lock(&stat_mutex);
|
||||
|
||||
++system_stat[system].alloc_count;
|
||||
++system_stat[system].alive_count;
|
||||
if (system_stat[system].alive_count > system_stat[system].alive_count_peak)
|
||||
system_stat[system].alive_count_peak = system_stat[system].alive_count;
|
||||
system_stat[system].size += size;
|
||||
if (system_stat[system].size > system_stat[system].size_peak)
|
||||
system_stat[system].size_peak = system_stat[system].size;
|
||||
}
|
||||
void UpdateStatDelete(size_t size, System system)
|
||||
{
|
||||
MutexLock lock(&stat_mutex);
|
||||
|
||||
system_stat[system].alive_count--;
|
||||
system_stat[system].size -= size;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
} // Alloc
|
||||
} // GS
|
||||
|
||||
|
||||
#endif // __ENABLE_ALLOCATION_STAT__
|
||||
|
||||
|
||||
#include "container/narray.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
class SmallBlockAllocatorPool
|
||||
{
|
||||
void *root;
|
||||
char *pool, *pool_end;
|
||||
|
||||
public:
|
||||
|
||||
bool Owns(void *p) const
|
||||
{ return (p >= (void *)pool) && (p < (void *)pool_end); }
|
||||
|
||||
void *Alloc()
|
||||
{
|
||||
if (!root)
|
||||
return NULL;
|
||||
|
||||
void *p = root;
|
||||
root = *((void **)root);
|
||||
return p;
|
||||
}
|
||||
void Free(void *p)
|
||||
{
|
||||
*((void **)p) = root;
|
||||
root = p;
|
||||
}
|
||||
|
||||
bool Init(size_t block_size, uint block_count)
|
||||
{
|
||||
Uninit();
|
||||
|
||||
pool = (char *)malloc(block_size * block_count);
|
||||
if (pool == NULL)
|
||||
return false;
|
||||
pool_end = pool + block_size * block_count;
|
||||
|
||||
for (uint n = 0; n < (block_count - 1); ++n)
|
||||
*((void **)(pool + n * block_size)) = (void *)(pool + (n + 1) * block_size);
|
||||
*((void **)(pool + (block_count - 1) * block_size)) = NULL;
|
||||
|
||||
root = (void *)pool;
|
||||
return true;
|
||||
}
|
||||
void Uninit()
|
||||
{
|
||||
free(pool);
|
||||
root = NULL;
|
||||
}
|
||||
|
||||
SmallBlockAllocatorPool()
|
||||
{
|
||||
pool = pool_end = NULL;
|
||||
root = NULL;
|
||||
}
|
||||
~SmallBlockAllocatorPool()
|
||||
{
|
||||
Uninit();
|
||||
}
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
class MixedBlockAllocator
|
||||
{
|
||||
SmallBlockAllocatorPool allocator[4];
|
||||
|
||||
public:
|
||||
|
||||
void *operator new (size_t size)
|
||||
{ return malloc(size); }
|
||||
void operator delete(void *addr)
|
||||
{ free(addr); }
|
||||
|
||||
void *Alloc(size_t size)
|
||||
{
|
||||
void *p = NULL;
|
||||
|
||||
if (size <= 8)
|
||||
p = allocator[0].Alloc();
|
||||
else if (size <= 16)
|
||||
p = allocator[1].Alloc();
|
||||
else if (size <= 32)
|
||||
p = allocator[2].Alloc();
|
||||
else if (size <= 64)
|
||||
p = allocator[3].Alloc();
|
||||
|
||||
return p ? p : malloc(size);
|
||||
}
|
||||
void Free(void *p)
|
||||
{
|
||||
if (allocator[0].Owns(p))
|
||||
allocator[0].Free(p);
|
||||
else if (allocator[1].Owns(p))
|
||||
allocator[1].Free(p);
|
||||
else if (allocator[2].Owns(p))
|
||||
allocator[2].Free(p);
|
||||
else if (allocator[3].Owns(p))
|
||||
allocator[3].Free(p);
|
||||
else
|
||||
free(p);
|
||||
}
|
||||
|
||||
bool Init()
|
||||
{
|
||||
allocator[0].Init(8, 16000); // 128k
|
||||
allocator[1].Init(16, 16000); // 256k
|
||||
allocator[2].Init(32, 8000); // 256k
|
||||
allocator[3].Init(64, 8000); // 512k
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if __ENABLE_GLOBAL_SBA__
|
||||
|
||||
MixedBlockAllocator *mixed_allocator = NULL;
|
||||
|
||||
MixedBlockAllocator *GetMixedAllocator()
|
||||
{
|
||||
if (!mixed_allocator)
|
||||
{
|
||||
mixed_allocator = new MixedBlockAllocator;
|
||||
mixed_allocator->Init();
|
||||
}
|
||||
return mixed_allocator;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void *operator new(size_t size)
|
||||
{
|
||||
__NSTAT_WRAPALLOC(GetMixedAllocator()->Alloc(size), Alloc::Global)
|
||||
}
|
||||
void operator delete(void *addr)
|
||||
{
|
||||
__NSTAT_WRAPDELETE(GetMixedAllocator()->Free(addr), Alloc::Global)
|
||||
}
|
||||
void *operator new [] (size_t size)
|
||||
{
|
||||
__NSTAT_WRAPALLOC(GetMixedAllocator()->Alloc(size), Alloc::Global)
|
||||
}
|
||||
void operator delete [] (void *addr)
|
||||
{
|
||||
__NSTAT_WRAPDELETE(GetMixedAllocator()->Free(addr), Alloc::Global)
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void *_align_alloc(size_t size, size_t align)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return _aligned_malloc(size, align);
|
||||
#else
|
||||
return malloc(size);
|
||||
#endif
|
||||
}
|
||||
void _align_free(void *p)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
_aligned_free(p);
|
||||
#else
|
||||
free(p);
|
||||
#endif
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
28
include/platform/assert/nassert.cpp
Normal file
28
include/platform/assert/nassert.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#if __PLATFORM_WINDOWS__
|
||||
#define WINDOWS_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include "assert/nassert.h"
|
||||
#include "nstring/nstring.h"
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GS::Assert::Trigger(const char *source, int line, const char *condition, const char *message)
|
||||
{
|
||||
String description = String::Format("%s\n\nFile: %s\nLine %d\n", condition, source, line);
|
||||
if (message)
|
||||
description += String("\nDetail: ") + message;
|
||||
|
||||
#if __PLATFORM_WINDOWS__
|
||||
MessageBoxA(NULL, description.c_str(), "Assertion failed!", MB_ICONSTOP);
|
||||
DebugBreak();
|
||||
#endif
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
215
include/platform/async/job.cpp
Normal file
215
include/platform/async/job.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "async/job.h"
|
||||
#include "memory/memory.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS::ASync;
|
||||
using namespace GS::Threading;
|
||||
|
||||
#ifndef _DEBUG
|
||||
#define __ENABLE_ITT_API__ 0
|
||||
#endif
|
||||
|
||||
#if __ENABLE_ITT_API__
|
||||
#include "ittnotify.h"
|
||||
static __itt_domain *domain = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void JobWorkerThread::Execute()
|
||||
{
|
||||
running.Set(1);
|
||||
|
||||
Thread::SetName(GS::String::Format("Job Worker Thread %d", worker_id));
|
||||
|
||||
while (running.Get() == 1)
|
||||
{
|
||||
// Execute as much jobs as possible until starvation.
|
||||
while (manager.ExecutePendingJob(worker_id));
|
||||
|
||||
// Wait for notification on the queue event.
|
||||
manager.job_queued_event.Wait();
|
||||
}
|
||||
|
||||
running.Set(0);
|
||||
}
|
||||
void JobWorkerThread::Stop()
|
||||
{ running.Set(2); }
|
||||
bool JobWorkerThread::IsRunning() const
|
||||
{ return running.Get() > 0; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool JobManager::CreateJobThreadPool(uint count)
|
||||
{
|
||||
FreeJobThreadPool();
|
||||
|
||||
if (!pool.Allocate(count))
|
||||
return false;
|
||||
|
||||
for (uint n = 0; n < count; ++n)
|
||||
if ((pool[n] = new JobWorkerThread(*this, n + 1)) == NULL)
|
||||
__ERR__(__LOG_E__ << "Failed to allocate a job worker thread.\n", false)
|
||||
|
||||
// Create workers.
|
||||
for (uint n = 0; n < count; ++n)
|
||||
if (!pool[n]->Start())
|
||||
__LOG_W__ << "Failed to create worker thread " << pool[n]->GetWorkerId() << ".\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
void JobManager::FreeJobThreadPool()
|
||||
{
|
||||
// Set thread exit flag.
|
||||
for (uint n = 0; n < pool.GetCount(); ++n)
|
||||
pool[n]->Stop();
|
||||
|
||||
// Trigger event so that the thread processes the exit flag.
|
||||
for (uint n = 0; n < pool.GetCount(); ++n)
|
||||
job_queued_event.Trigger();
|
||||
|
||||
// Join threads.
|
||||
for (uint n = 0; n < pool.GetCount(); ++n)
|
||||
if (!pool[n]->IsRunning())
|
||||
delete pool[n];
|
||||
|
||||
pool.Free();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool JobManager::EnqueueJob(Job *job, JobGroup *group)
|
||||
{
|
||||
if (pool.GetCount() == 0)
|
||||
{
|
||||
job->Execute(0);
|
||||
job->done.Set(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
job->done.Set(0);
|
||||
|
||||
if (group)
|
||||
{
|
||||
MutexLock lock(group->job_list_mutex);
|
||||
group->job_list.Add(job);
|
||||
}
|
||||
{
|
||||
#if __USE_LOCK_FREE_JOB_QUEUE__
|
||||
while (!pending_queue.enqueue(job)) {}
|
||||
#else
|
||||
nMutexLock lock(pending_queue_mutex);
|
||||
pending_queue.Push(job);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
job_queued_event.Trigger(); // wake workers
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool JobManager::JoinJob(Job *job, bool blocking)
|
||||
{
|
||||
if (job)
|
||||
while (job->done.Get() == 0) // spinlock
|
||||
if (!blocking)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool JobManager::JoinGroup(JobGroup *group, bool blocking)
|
||||
{
|
||||
if (group)
|
||||
for (bool done = false; !done; ) // spinlock
|
||||
{
|
||||
done = true;
|
||||
{
|
||||
MutexLock glock(group->job_list_mutex);
|
||||
ListForeachPtr(Job *, job, group->job_list)
|
||||
if (job->done.Get() == 0)
|
||||
{
|
||||
done = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!blocking)
|
||||
return done;
|
||||
|
||||
Thread::Switch();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool JobManager::ExecutePendingJob(uint worker_id)
|
||||
{
|
||||
// Look for a job to execute.
|
||||
Job *job = NULL;
|
||||
{
|
||||
#if __USE_LOCK_FREE_JOB_QUEUE__
|
||||
pending_queue.dequeue(job);
|
||||
#else
|
||||
nMutexLock pending_lock(pending_queue_mutex);
|
||||
if (pending_queue.GetCount() > 0)
|
||||
{
|
||||
job = pending_queue.Top();
|
||||
pending_queue.Pop();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Execute job.
|
||||
if (job)
|
||||
{
|
||||
#if __ENABLE_ITT_API__
|
||||
__itt_task_begin(domain, __itt_null, __itt_null, __itt_string_handle_create(job->name));
|
||||
#endif
|
||||
|
||||
// job->time_start = Platform::Get().GetTime();
|
||||
|
||||
job->Execute(worker_id);
|
||||
job->done.Set(1);
|
||||
|
||||
// job->time_end = Platform::Get().GetTime();
|
||||
|
||||
Thread::Switch(); // let other workers do their job
|
||||
|
||||
#if __ENABLE_ITT_API__
|
||||
__itt_task_end(domain);
|
||||
#endif
|
||||
}
|
||||
return asbool(job);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uint JobManager::GetWorkerPoolSize() const
|
||||
{ return pool.GetCount(); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
JobManager::JobManager() : pending_queue(256)
|
||||
{
|
||||
#if __ENABLE_ITT_API__
|
||||
domain = __itt_domain_create("GS.JobManager");
|
||||
#endif
|
||||
|
||||
#if (__USE_LOCK_FREE_JOB_QUEUE__ == 0)
|
||||
pending_queue_mutex = new nMutex;
|
||||
#endif
|
||||
}
|
||||
JobManager::~JobManager()
|
||||
{ FreeJobThreadPool(); }
|
||||
JobGroup::JobGroup()
|
||||
{ job_list_mutex = new Mutex; }
|
||||
//------------------------------------------------------------------------------
|
||||
160
include/platform/filesystem/data_store.cpp
Normal file
160
include/platform/filesystem/data_store.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "filesystem/data_store.h"
|
||||
#include "rand/rand.h"
|
||||
#include "memory/nauto_ptr.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::IO;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
DataStore::Entry *DataStore::GetEntry(const String &id) const
|
||||
{
|
||||
ListForeachPtr(Entry *, e, entries)
|
||||
if (e->id == id)
|
||||
return e;
|
||||
return NULL;
|
||||
}
|
||||
String DataStore::GetNewId()
|
||||
{
|
||||
for ( ; ; ++id_seed)
|
||||
{
|
||||
String id = String::Format("store_%012d", id_seed);
|
||||
if (GetEntry(id) == NULL)
|
||||
return id;
|
||||
}
|
||||
return String();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
size_t DataStore::GetEntrySize(const String &id) const
|
||||
{
|
||||
if (Entry *e = GetEntry(id))
|
||||
return e->size;
|
||||
return 0;
|
||||
}
|
||||
size_t DataStore::GetStoreSize() const
|
||||
{
|
||||
size_t size = 0;
|
||||
ListForeachPtr(Entry *, e, entries)
|
||||
size += e->size;
|
||||
return size;
|
||||
}
|
||||
size_t DataStore::GetFreeStore() const
|
||||
{ return limit - GetStoreSize(); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
String DataStore::Reserve(size_t size)
|
||||
{
|
||||
Threading::MutexLock lock(&mutex);
|
||||
|
||||
if (limit > 0) // enforce size limit
|
||||
{
|
||||
size_t store_size = GetStoreSize();
|
||||
if (size > (limit - store_size))
|
||||
return String(); // store is full
|
||||
}
|
||||
|
||||
// Reserve a new entry.
|
||||
Entry *entry = new Entry;
|
||||
|
||||
entry->id = GetNewId();
|
||||
entry->size = size;
|
||||
entries.Add(entry);
|
||||
|
||||
return entry->id;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool DataStore::Store(const String &id, const void *data, size_t size, const char *user)
|
||||
{
|
||||
Threading::MutexLock lock(&mutex);
|
||||
|
||||
Entry *entry = GetEntry(id);
|
||||
if ((entry == NULL) || (entry->size != size))
|
||||
return false; // invalid id/store size
|
||||
|
||||
lock.Unlock();
|
||||
|
||||
entry->user = user;
|
||||
|
||||
AutoPtr <Handle> h(io->Open(id, ModeWrite));
|
||||
return h.IsValid() && (h->Write(data, size) == size);
|
||||
}
|
||||
bool DataStore::Free(const String &id)
|
||||
{
|
||||
Threading::MutexLock lock(&mutex);
|
||||
|
||||
Entry *entry = GetEntry(id);
|
||||
if (entry == NULL)
|
||||
return false; // invalid id
|
||||
|
||||
if (!io->Delete(id))
|
||||
return false;
|
||||
|
||||
return entries.Remove(entry);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Store format
|
||||
//
|
||||
// 18 bytes - id
|
||||
// 4 bytes - size in bytes
|
||||
// -----------------------------
|
||||
bool DataStore::Load(const char *path)
|
||||
{
|
||||
AutoPtr <Handle> h(io->Open(path));
|
||||
if (h.IsNull())
|
||||
return true; // nothing to restore
|
||||
|
||||
entries.Clear();
|
||||
|
||||
char id[18];
|
||||
while (!h->IsEOF())
|
||||
{
|
||||
if (h->Read((void *)id, 18) != 18)
|
||||
return false;
|
||||
|
||||
Entry *e = new Entry;
|
||||
|
||||
e->id.Set(id, id + 18);
|
||||
e->size = h->Read <size_t> ();
|
||||
|
||||
uint user_data_size = h->Read <uint> ();
|
||||
if (!e->user.Allocate(user_data_size))
|
||||
return false;
|
||||
|
||||
h->Read((void *)e->user.c_str(), user_data_size);
|
||||
|
||||
entries.Add(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool DataStore::Save(const char *path)
|
||||
{
|
||||
AutoPtr <Handle> h(io->Open(path, ModeWrite));
|
||||
if (h.IsNull())
|
||||
return false;
|
||||
|
||||
ListForeachPtr(Entry *, e, entries)
|
||||
{
|
||||
h->Write(e->id.c_str(), 18);
|
||||
h->Write(&e->size, 4);
|
||||
|
||||
uint user_data_size = e->user.Len();
|
||||
h->Write(user_data_size);
|
||||
if (user_data_size > 0)
|
||||
h->Write(e->user.c_str(), user_data_size);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
218
include/platform/filesystem/filesystem.cpp
Normal file
218
include/platform/filesystem/filesystem.cpp
Normal file
@ -0,0 +1,218 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "filesystem/io_handle.h"
|
||||
#include "log/log.h"
|
||||
|
||||
|
||||
#if __PLATFORM_POSIX__
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#elif __PLATFORM_WINDOWS__
|
||||
#include <direct.h>
|
||||
#endif
|
||||
|
||||
#include "filesystem/io_cfile.h"
|
||||
#include "memory/nauto_ptr.h"
|
||||
|
||||
|
||||
using GS::String;
|
||||
using namespace GS::IO;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Filesystem::Exists(const char *uri) const
|
||||
{
|
||||
AutoPtr <Handle> h(Open(uri));
|
||||
return h.IsValid();
|
||||
}
|
||||
size_t Filesystem::FileSize(const char *uri) const
|
||||
{
|
||||
AutoPtr <Handle> h(Open(uri));
|
||||
return h.IsNull() ? 0 : h->GetSize();
|
||||
}
|
||||
bool Filesystem::FileLoad(const char *uri, GS::Array <char> &buffer, bool verbose) const
|
||||
{
|
||||
AutoPtr <Handle> h(Open(uri));
|
||||
if (h.IsNull())
|
||||
{
|
||||
if (verbose)
|
||||
__LOG_W__ << "Failed to open '" << uri << "'.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Warning: Do not load through IO::Base::FileLoad. That would create another handle!
|
||||
size_t size = h->GetSize();
|
||||
if (!buffer.Allocate(size))
|
||||
__ERR__(__LOG_W__ << "Failed to allocate memory to load '" << uri << "'.\n", false)
|
||||
|
||||
return asbool(h->Read(buffer.c_ptr(), size) == size);
|
||||
}
|
||||
bool Filesystem::FileSave(const char *uri, const GS::Array <char> &buffer) const
|
||||
{
|
||||
AutoPtr <Handle> h(Open(uri, ModeWrite));
|
||||
if (h.IsNull())
|
||||
__ERR__(__LOG_W__ << "Failed to open '" << uri << "'.\n", false)
|
||||
return asbool(h->Write(buffer.c_ptr(), buffer.GetSize()) == buffer.GetSize());
|
||||
}
|
||||
bool Filesystem::FileCopy(const char *src, const char *dst) const
|
||||
{
|
||||
Array <char> buffer;
|
||||
return FileLoad(src, buffer) && FileSave(dst, buffer);
|
||||
}
|
||||
bool Filesystem::FileMove(const char *src, const char *dst) const
|
||||
{
|
||||
Array <char> buffer;
|
||||
return FileLoad(src, buffer) && FileSave(dst, buffer) && Delete(src);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
String Filesystem::MapToAbsolute(const char *uri) const
|
||||
{
|
||||
String _uri(uri);
|
||||
ListForeachPtr(MountPoint *, m, mount_list)
|
||||
if (_uri.StartsWith(m->mount_point))
|
||||
return m->io_sys->MapToAbsolute(_uri.Mid(m->mount_point.Len())).CleanFilePath();
|
||||
|
||||
ListForeachPtr(Base *, i, root_mount)
|
||||
{
|
||||
AutoPtr <Handle> h(i->Open(_uri));
|
||||
if (h.IsValid())
|
||||
return i->MapToAbsolute(_uri).CleanFilePath();
|
||||
}
|
||||
return _uri;
|
||||
}
|
||||
String Filesystem::StripRootPath(const char *path) const
|
||||
{
|
||||
String _path(path);
|
||||
_path.FileCleanName();
|
||||
ListForeachPtr(Base *, i, root_mount)
|
||||
{
|
||||
String rpath = i->MapToRelative(_path);
|
||||
if (!rpath.IsEmpty())
|
||||
if (rpath != _path)
|
||||
return rpath[0] == '/' ? rpath.Mid(1) : rpath; // Ensure no leading '/' remains.
|
||||
}
|
||||
return _path;
|
||||
}
|
||||
bool Filesystem::Mount(Base *io_sys, const char *mount_point)
|
||||
{
|
||||
if (mount_point)
|
||||
{
|
||||
ListForeachPtr(MountPoint *, m, mount_list)
|
||||
if (m->mount_point == mount_point)
|
||||
{
|
||||
delete io_sys;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return asbool(mount_list.Prepend(new MountPoint(mount_point, io_sys)));
|
||||
}
|
||||
else
|
||||
{
|
||||
ListForeachPtr(Base *, i, root_mount)
|
||||
if (i == io_sys)
|
||||
__ERR__(__LOG_E__ << "Cannot mount IO system twice as root.\n", false)
|
||||
|
||||
return asbool(root_mount.Prepend(io_sys));
|
||||
}
|
||||
}
|
||||
void Filesystem::Unmount(const char *mount_point)
|
||||
{ Unmount(GetIOSystem(mount_point)); }
|
||||
void Filesystem::Unmount(Base *io_sys)
|
||||
{
|
||||
ListForeachPtr(MountPoint *, m, mount_list)
|
||||
if (m->io_sys.c_ptr() == io_sys)
|
||||
mount_list.Remove(m);
|
||||
ListForeachPtr(Base *, i, root_mount)
|
||||
if (i == io_sys)
|
||||
root_mount.Remove(i);
|
||||
}
|
||||
void Filesystem::UnmountAll()
|
||||
{
|
||||
ListForeachPtr(MountPoint *, m, mount_list)
|
||||
mount_list.Remove(m);
|
||||
while (List <Base *> ::Item *m = root_mount.GetRoot())
|
||||
root_mount.Remove(m);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Base *Filesystem::GetIOSystem(const char *mount_point) const
|
||||
{
|
||||
ListForeachPtr(MountPoint *, m, mount_list)
|
||||
if (m->mount_point == mount_point)
|
||||
return m->io_sys;
|
||||
return NULL;
|
||||
}
|
||||
const char *Filesystem::GetMountPoint(const Base *io_sys) const
|
||||
{
|
||||
ListForeachPtr(MountPoint *, m, mount_list)
|
||||
if (m->io_sys == io_sys)
|
||||
return m->mount_point;
|
||||
return NULL;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Handle *Filesystem::Open(const char *uri, Mode mode) const
|
||||
{
|
||||
String _uri(uri);
|
||||
|
||||
if (_uri.IsEmpty())
|
||||
return NULL;
|
||||
|
||||
ListForeachPtr(MountPoint *, m, mount_list)
|
||||
if (_uri.StartsWith(m->mount_point))
|
||||
return m->io_sys->Open(_uri.Mid(m->mount_point.Len()), mode);
|
||||
ListForeachPtr(Base *, i, root_mount)
|
||||
if (Handle *h = i->Open(uri, mode))
|
||||
return h;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
void Filesystem::Close(Handle *h) const
|
||||
{
|
||||
ListForeachPtr(MountPoint *, m, mount_list)
|
||||
if (m->io_sys.c_ptr() == h->GetIOSystem())
|
||||
m->io_sys->Close(h);
|
||||
ListForeachPtr(Base *, i, root_mount)
|
||||
if (i == h->GetIOSystem())
|
||||
i->Close(h);
|
||||
}
|
||||
bool Filesystem::Delete(const char *uri) const
|
||||
{
|
||||
AutoPtr <Handle> h(Open(uri));
|
||||
if (h.IsValid())
|
||||
{
|
||||
Base *io_sys = h->GetIOSystem();
|
||||
h = NULL;
|
||||
return io_sys->Delete(uri);
|
||||
}
|
||||
else
|
||||
return asbool(unlink(uri) == 0);
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Filesystem::MkDir(const char *path) const
|
||||
{
|
||||
String _path(path);
|
||||
|
||||
if (_path.IsEmpty())
|
||||
return false;
|
||||
|
||||
ListForeachPtr(MountPoint *, m, mount_list)
|
||||
if (_path.StartsWith(m->mount_point))
|
||||
return m->io_sys->MkDir(_path.Mid(m->mount_point.Len()));
|
||||
|
||||
// [EJ] No creation on a root filesystem here!
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
984
include/platform/filesystem/ftp_lib.cpp
Normal file
984
include/platform/filesystem/ftp_lib.cpp
Normal file
@ -0,0 +1,984 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "filesystem/ftp_lib.h"
|
||||
#include "nstring/nstring.h"
|
||||
#include "platform_config.h"
|
||||
#include "alloc/ialloc.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
#define ConnectionBufferSize 1024
|
||||
|
||||
#if __PLATFORM_WINDOWS__
|
||||
|
||||
#define SETSOCKOPT_OPTVAL_TYPE (const char *)
|
||||
#define net_read(x,y,z) recv(x,(char*)y,z,0)
|
||||
#define net_write(x,y,z) send(x,(char*)y,z,0)
|
||||
#define net_close closesocket
|
||||
typedef int socklen_t;
|
||||
|
||||
#elif (__PLATFORM_LINUX__ || __PLATFORM_OSX__)
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define SETSOCKOPT_OPTVAL_TYPE (void *)
|
||||
#define net_read read
|
||||
#define net_write write
|
||||
#define net_close close
|
||||
#define SOCKET int
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
#if (__PLATFORM_WINDOWS__ || __PLATFORM_LINUX__ || __PLATFORM_OSX__)
|
||||
|
||||
|
||||
#define FTP_PROPAGATE_ERROR__(__C__) { State s = __C__; if (s != FtpOk) return s; }
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
//----------------------------
|
||||
FtpConnection::FtpConnection()
|
||||
//----------------------------
|
||||
{
|
||||
handle = -1;
|
||||
ready = false;
|
||||
|
||||
buffer = 0;
|
||||
buffer_usage = 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------
|
||||
void FtpConnection::FreeBuffer()
|
||||
//---------------------------------------------
|
||||
{ _safe_delete_array(buffer); }
|
||||
|
||||
//-------------------------------------------------
|
||||
bool FtpConnection::AllocateBuffer()
|
||||
//-------------------------------------------------
|
||||
{
|
||||
FreeBuffer();
|
||||
return (buffer = new char[ConnectionBufferSize]) != NULL ? true : false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
FtpLibrary::State FtpLibrary::WaitSocket(FtpConnection *connection)
|
||||
//-------------------------------------------------------------------
|
||||
{
|
||||
fd_set fd, *rfd = NULL, *wfd = NULL;
|
||||
|
||||
FD_ZERO(&fd);
|
||||
if (connection->direction == FtpConnection::Upload)
|
||||
wfd = &fd;
|
||||
else
|
||||
rfd = &fd;
|
||||
|
||||
forever
|
||||
{
|
||||
FD_SET(connection->handle, &fd);
|
||||
|
||||
// 5 seconds timeout.
|
||||
timeval tv;
|
||||
tv.tv_sec = 4;
|
||||
tv.tv_usec = 100000;
|
||||
|
||||
SOCKET rv = select((int)(connection->handle + 1), rfd, wfd, NULL, &tv);
|
||||
|
||||
if (rv == -1)
|
||||
return FtpError;
|
||||
else if (!rv)
|
||||
return FtpSocketTimeout;
|
||||
else
|
||||
break;
|
||||
/*
|
||||
if (!IdleCallback())
|
||||
FtpSocketTimeout;
|
||||
*/
|
||||
}
|
||||
return FtpOk;
|
||||
}
|
||||
|
||||
//---------------------------------------------------
|
||||
bool FtpLibrary::CheckResponse(char c)
|
||||
//---------------------------------------------------
|
||||
{
|
||||
char match[5];
|
||||
int length;
|
||||
if (ReadASCII(response, 256, &master_connection, length) != FtpOk)
|
||||
return false;
|
||||
|
||||
if (response[3] == '-')
|
||||
{
|
||||
strncpy(match, response, 3);
|
||||
match[3] = ' ';
|
||||
match[4] = '\0';
|
||||
|
||||
do
|
||||
{
|
||||
if (ReadASCII(response, 256, &master_connection, length) != FtpOk)
|
||||
return false;
|
||||
} while (strncmp(response, match, 4));
|
||||
}
|
||||
return (response[0] == c) ? true : false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
bool FtpLibrary::Connect(const char *host)
|
||||
//-------------------------------------------------------
|
||||
{
|
||||
sockaddr_in sin;
|
||||
memset(&sin,0,sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
|
||||
char *lhost = strdup(host), *pnum = strchr(lhost,':');
|
||||
|
||||
servent *pse;
|
||||
if (!pnum)
|
||||
{
|
||||
if ((pse = getservbyname("ftp", "tcp")) == NULL)
|
||||
__ERR__(__LOG__ << "[!] (FTP) Failed to get service port.\n", false)
|
||||
sin.sin_port = pse->s_port;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pnum++ = 0;
|
||||
if (isdigit(*pnum))
|
||||
sin.sin_port = htons((u_short)atoi(pnum));
|
||||
else
|
||||
{
|
||||
pse = getservbyname(pnum, "tcp");
|
||||
sin.sin_port = pse->s_port;
|
||||
}
|
||||
}
|
||||
|
||||
#if __PLATFORM_WINDOWS__
|
||||
if ((sin.sin_addr.s_addr = inet_addr(lhost)) == -1)
|
||||
#else
|
||||
if (!inet_aton(lhost, &sin.sin_addr))
|
||||
#endif
|
||||
{
|
||||
hostent *phe;
|
||||
if ((phe = gethostbyname(lhost)) == NULL)
|
||||
__ERR__(__LOG__ << "[!] (FTP) Failed to resolve host.\n", false)
|
||||
memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length);
|
||||
}
|
||||
free(lhost);
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
#define __ConnectError__(_S_)\
|
||||
{ __LOG__ << _S_; net_close(master_connection.handle); master_connection.handle = 0; return false; }
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
|
||||
master_connection.handle = (int)socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (master_connection.handle == -1)
|
||||
__ConnectError__("[!] (FTP) Failed to create socket.\n")
|
||||
|
||||
int on = 1;
|
||||
if (setsockopt(master_connection.handle, SOL_SOCKET, SO_REUSEADDR, SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1)
|
||||
__ConnectError__("[!] (FTP) Set socket option failed.\n")
|
||||
if (connect(master_connection.handle, (struct sockaddr *)&sin, sizeof(sin)) == -1)
|
||||
__ConnectError__("[!] (FTP) Socket failed to connect.\n")
|
||||
if (!CheckResponse('2'))
|
||||
__ConnectError__("")
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
bool FtpLibrary::CheckPASVResponse(unsigned char *v)
|
||||
//-----------------------------------------------------------------
|
||||
{
|
||||
sockaddr sa;
|
||||
socklen_t l = sizeof(sa);
|
||||
|
||||
if (getpeername(master_connection.handle, &sa, &l) == -1)
|
||||
{
|
||||
net_close(master_connection.handle);
|
||||
return false;
|
||||
}
|
||||
for (int i = 2; i < 6; ++i)
|
||||
v[i] = sa.sa_data[i];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
bool FtpLibrary::FtpSendCmd(const char *command, char expresp)
|
||||
//---------------------------------------------------------------------------
|
||||
{
|
||||
if (!master_connection.handle)
|
||||
return 0;
|
||||
|
||||
char ftp_command[256];
|
||||
_snprintf(ftp_command, 255, "%s\r\n", command);
|
||||
if (net_write(master_connection.handle, ftp_command, (int)strlen(ftp_command)) <= 0)
|
||||
return false;
|
||||
|
||||
SendCommandCallback(ftp_command);
|
||||
return CheckResponse(expresp);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
bool FtpLibrary::Login(const char *user, const char *password)
|
||||
//---------------------------------------------------------------------------
|
||||
{
|
||||
char ftp_command[64];
|
||||
|
||||
// Send user.
|
||||
_snprintf(ftp_command, 63, "USER %s", user);
|
||||
if (!FtpSendCmd(ftp_command, '3'))
|
||||
{
|
||||
if (*GetLastResponse() == '2')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send password.
|
||||
_snprintf(ftp_command, 63, "PASS %s", password);
|
||||
return FtpSendCmd(ftp_command, '2');
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
FtpConnection *FtpLibrary::CreatePORTConnection(TransferMode mode, FtpConnection::Direction dir, char *connection_command)
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
union
|
||||
{
|
||||
sockaddr sa;
|
||||
sockaddr_in in;
|
||||
} sin;
|
||||
|
||||
// Create the new connection.
|
||||
FtpConnection *connection = new FtpConnection;
|
||||
if (!connection)
|
||||
__ERR__(__LOG__ << "[!] (FTP) Failed to allocate new connection object.\n", NULL)
|
||||
|
||||
// Get socket from the master connection.
|
||||
socklen_t l = sizeof(sin);
|
||||
if (getsockname(master_connection.handle, &sin.sa, &l) < 0)
|
||||
return connection;
|
||||
|
||||
// Create socket.
|
||||
connection->handle = (int)socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (connection->handle == -1)
|
||||
return connection;
|
||||
|
||||
// Set socket options.
|
||||
int on = 1;
|
||||
if (setsockopt(connection->handle, SOL_SOCKET, SO_REUSEADDR, SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1)
|
||||
return connection;
|
||||
|
||||
linger lng = { 0, 0 };
|
||||
if (setsockopt(connection->handle, SOL_SOCKET, SO_LINGER, SETSOCKOPT_OPTVAL_TYPE &lng, sizeof(lng)) == -1)
|
||||
return connection;
|
||||
|
||||
// Bind socket.
|
||||
sin.in.sin_port = 0;
|
||||
if (
|
||||
(bind(connection->handle, &sin.sa, sizeof(sin)) == -1) ||
|
||||
(listen(connection->handle, 1) < 0) ||
|
||||
(getsockname(connection->handle, &sin.sa, &l) < 0)
|
||||
)
|
||||
return connection;
|
||||
|
||||
// Open PORT connection.
|
||||
char ftp_command[256];
|
||||
_snprintf(ftp_command, 255, "PORT %hhu,%hhu,%hhu,%hhu,%hhu,%hhu",
|
||||
(unsigned char)sin.sa.sa_data[2],
|
||||
(unsigned char)sin.sa.sa_data[3],
|
||||
(unsigned char)sin.sa.sa_data[4],
|
||||
(unsigned char)sin.sa.sa_data[5],
|
||||
(unsigned char)sin.sa.sa_data[0],
|
||||
(unsigned char)sin.sa.sa_data[1] );
|
||||
|
||||
if (!FtpSendCmd(ftp_command, '2'))
|
||||
return connection;
|
||||
|
||||
// Handle resuming.
|
||||
if (offset)
|
||||
{
|
||||
_snprintf(ftp_command, 255, "REST %lld", offset);
|
||||
if (!FtpSendCmd(ftp_command, '3'))
|
||||
return connection; // TODO allow for a full restart here?
|
||||
}
|
||||
|
||||
// Allocate buffer for binary transaction.
|
||||
if ((mode == TransferASCII) && !connection->AllocateBuffer())
|
||||
return connection;
|
||||
|
||||
// Finally send the connection command.
|
||||
if (!FtpSendCmd(connection_command, '1'))
|
||||
return connection;
|
||||
|
||||
// Connection is ready.
|
||||
connection->direction = dir;
|
||||
connection->ready = true;
|
||||
return connection;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
FtpConnection *FtpLibrary::CreatePASVConnection(TransferMode mode, FtpConnection::Direction dir, char *connection_command)
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
// Set PASV mode.
|
||||
if (!FtpSendCmd("PASV", '2'))
|
||||
return NULL;
|
||||
|
||||
// Check server answer.
|
||||
char *cp = strchr(response,'(');
|
||||
if (!cp)
|
||||
return NULL;
|
||||
|
||||
unsigned char v[6];
|
||||
sscanf(++cp, "%hhu,%hhu,%hhu,%hhu,%hhu,%hhu", &v[2], &v[3], &v[4], &v[5], &v[0], &v[1]);
|
||||
if (correctpasv && !CheckPASVResponse(v))
|
||||
__ERR__(__LOG__ << "[!] (FTP) Incorrect PASV response.\n", NULL)
|
||||
|
||||
struct sockaddr sa;
|
||||
sa.sa_family = AF_INET;
|
||||
sa.sa_data[2] = v[2];
|
||||
sa.sa_data[3] = v[3];
|
||||
sa.sa_data[4] = v[4];
|
||||
sa.sa_data[5] = v[5];
|
||||
sa.sa_data[0] = v[0];
|
||||
sa.sa_data[1] = v[1];
|
||||
|
||||
// Handle resume.
|
||||
char ftp_command[256];
|
||||
|
||||
if (offset)
|
||||
{
|
||||
_snprintf(ftp_command, 255, "REST %lld", offset);
|
||||
if (!FtpSendCmd(ftp_command, '3'))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create the new connection.
|
||||
FtpConnection *connection = new FtpConnection;
|
||||
if (!connection)
|
||||
__ERR__(__LOG__ << "[!] (FTP) Failed to allocate new connection object.\n", NULL)
|
||||
|
||||
// Create socket.
|
||||
int on = 1;
|
||||
linger lng = { 0, 0 };
|
||||
connection->handle = (int)socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
|
||||
if (
|
||||
(connection->handle == -1) ||
|
||||
(setsockopt(connection->handle, SOL_SOCKET, SO_REUSEADDR, SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1) ||
|
||||
(setsockopt(connection->handle, SOL_SOCKET, SO_LINGER, SETSOCKOPT_OPTVAL_TYPE &lng, sizeof(lng)) == -1)
|
||||
)
|
||||
return connection;
|
||||
|
||||
// Setup connection.
|
||||
_snprintf(ftp_command, 255, "%s\r\n", connection_command);
|
||||
if (net_write(master_connection.handle, ftp_command, (int)strlen(ftp_command)) <= 0)
|
||||
return connection;
|
||||
|
||||
// Connect socket.
|
||||
if ((connect(connection->handle, &sa, sizeof(sa)) == -1) || !CheckResponse('1'))
|
||||
return connection;
|
||||
|
||||
// Allocate buffer for binary transaction.
|
||||
if ((mode == TransferASCII) && !connection->AllocateBuffer())
|
||||
return connection;
|
||||
|
||||
// Connection is ready.
|
||||
connection->direction = dir;
|
||||
connection->ready = true;
|
||||
return connection;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool FtpLibrary::FtpAcceptConnection(FtpConnection *connection)
|
||||
//----------------------------------------------------------------------------
|
||||
{
|
||||
// Reset all connections.
|
||||
fd_set mask;
|
||||
|
||||
FD_ZERO(&mask);
|
||||
FD_SET(master_connection.handle, &mask);
|
||||
FD_SET(connection->handle, &mask);
|
||||
|
||||
// Setup timeout.
|
||||
timeval tv;
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = 30;
|
||||
|
||||
// Select handle.
|
||||
int i = (int)master_connection.handle;
|
||||
if (i < connection->handle)
|
||||
i = connection->handle;
|
||||
i = select((int)(i + 1), &mask, NULL, NULL, &tv);
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case -1: // Error.
|
||||
strncpy(response, strerror(errno), sizeof(response));
|
||||
break;
|
||||
|
||||
case 0: // Time out.
|
||||
strcpy(response, "Time out waiting for connection.");
|
||||
break;
|
||||
|
||||
default:
|
||||
if (FD_ISSET(connection->handle, &mask))
|
||||
{
|
||||
sockaddr addr;
|
||||
socklen_t l = sizeof(addr);
|
||||
int handle = (int)accept(connection->handle, &addr, &l);
|
||||
i = errno;
|
||||
net_close(connection->handle);
|
||||
|
||||
if (handle > 0)
|
||||
{
|
||||
connection->handle = handle;
|
||||
return true;
|
||||
}
|
||||
|
||||
strncpy(response, strerror((int)i), sizeof(response));
|
||||
connection->handle = 0;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
if (FD_ISSET(connection->handle, &mask))
|
||||
CheckResponse('2');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
net_close(connection->handle);
|
||||
connection->handle = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FtpConnection *FtpLibrary::CreateConnection(const char *path, AccessType type, TransferMode mode)
|
||||
{
|
||||
if (!path && ((type == AccessFileWrite) || (type == AccessFileRead) || (type == AccessFileReadAppend) || (type == AccessFileWriteAppend)))
|
||||
__ERR__(__LOG__ << "[!] (FTP) Missing path argument.\n", NULL)
|
||||
|
||||
// Setup transfer mode.
|
||||
char ftp_command[256];
|
||||
_snprintf(ftp_command, 255, "TYPE %c", mode);
|
||||
if (!FtpSendCmd(ftp_command, '2'))
|
||||
__ERR__(__LOG__ << "[!] (FTP) Failed to set tranfer mode.\n", NULL)
|
||||
|
||||
// Select sub command.
|
||||
const char *sub_command;
|
||||
FtpConnection::Direction direction = FtpConnection::Download;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case AccessDir:
|
||||
sub_command = "NLST";
|
||||
break;
|
||||
|
||||
case AccessDirVerbose:
|
||||
sub_command = "LIST -aL";
|
||||
break;
|
||||
|
||||
case AccessFileReadAppend:
|
||||
case AccessFileRead:
|
||||
sub_command = "RETR";
|
||||
break;
|
||||
|
||||
case AccessFileWriteAppend:
|
||||
case AccessFileWrite:
|
||||
sub_command = "STOR";
|
||||
direction = FtpConnection::Upload;
|
||||
break;
|
||||
|
||||
default:
|
||||
__ERR__(__LOG__ << "[!] (FTP) Invalid access type.\n", NULL)
|
||||
}
|
||||
|
||||
// Append path.
|
||||
if (path)
|
||||
_snprintf(ftp_command, 255, "%s %s", sub_command, path);
|
||||
|
||||
// Open connection.
|
||||
FtpConnection *connection = NULL;
|
||||
|
||||
switch (connection_mode)
|
||||
{
|
||||
case ConnectionPASV:
|
||||
connection = CreatePASVConnection(mode, direction, ftp_command);
|
||||
break;
|
||||
|
||||
case ConnectionPORT:
|
||||
connection = CreatePORTConnection(mode, direction, ftp_command);
|
||||
if (!connection || !connection->ready)
|
||||
break;
|
||||
|
||||
if (!FtpAcceptConnection(connection))
|
||||
{
|
||||
CloseConnection(connection);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
bool FtpLibrary::CloseConnection(FtpConnection *connection)
|
||||
{
|
||||
// Sanity check.
|
||||
if (connection == &master_connection)
|
||||
return false;
|
||||
|
||||
// Purge writing cache.
|
||||
int length;
|
||||
if (connection->direction == FtpConnection::Upload)
|
||||
if (connection->buffer)
|
||||
WriteASCII(NULL, 0, connection, length);
|
||||
|
||||
shutdown(connection->handle, 2);
|
||||
net_close(connection->handle);
|
||||
_safe_delete(connection);
|
||||
|
||||
return CheckResponse('2');
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FtpLibrary::State FtpLibrary::ReadASCII(char *buf, int max, FtpConnection *connection, int &total_read_count)
|
||||
{
|
||||
/// TODO
|
||||
// Early exit case.
|
||||
if (max == 0)
|
||||
return FtpOk;
|
||||
if ((connection != &master_connection) && (connection->direction != FtpConnection::Download))
|
||||
return FtpError;
|
||||
|
||||
// Read.
|
||||
total_read_count = 0;
|
||||
char *p_buffer = buf;
|
||||
|
||||
forever
|
||||
{
|
||||
// Check available data on cache.
|
||||
if (connection->buffer_usage > 0)
|
||||
{
|
||||
// Determine read size.
|
||||
char *eol = (char *)memchr(connection->buffer, '\n', connection->buffer_usage);
|
||||
int read_size = (int)(eol ? eol - connection->buffer + 1 : connection->buffer_usage);
|
||||
|
||||
if (read_size > (max - 1))
|
||||
read_size = max - 1;
|
||||
|
||||
// Perform reading.
|
||||
memcpy(p_buffer, connection->buffer, read_size);
|
||||
|
||||
max -= read_size;
|
||||
total_read_count += read_size;
|
||||
p_buffer += read_size;
|
||||
|
||||
// Update cache.
|
||||
if (read_size < connection->buffer_usage)
|
||||
memcpy(connection->buffer, &connection->buffer[read_size], connection->buffer_usage - read_size);
|
||||
connection->buffer_usage -= read_size;
|
||||
|
||||
// Catch end of buffer.
|
||||
if ((max == 1) || eol)
|
||||
{
|
||||
p_buffer[0] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait socket.
|
||||
FTP_PROPAGATE_ERROR__(WaitSocket(connection))
|
||||
|
||||
// Fill cache.
|
||||
int buffer_left = (ConnectionBufferSize - connection->buffer_usage) - 1,
|
||||
read_count = net_read(connection->handle, &connection->buffer[connection->buffer_usage], buffer_left);
|
||||
|
||||
connection->buffer_usage += read_count;
|
||||
|
||||
if (read_count == -1)
|
||||
__ERR__(__LOG__ << "[!] (FTP) Read error.\n", FtpError)
|
||||
else if (!read_count)
|
||||
break; // EOF
|
||||
}
|
||||
return FtpOk;
|
||||
}
|
||||
FtpLibrary::State FtpLibrary::WriteASCII(char *output, int length, FtpConnection *connection, int &x)
|
||||
{
|
||||
/// TODO
|
||||
if (connection->direction != FtpConnection::Upload)
|
||||
return FtpError;
|
||||
|
||||
FTP_PROPAGATE_ERROR__(WaitSocket(connection))
|
||||
if ((x = net_write(connection->handle, output, length)) != length)
|
||||
return FtpError;
|
||||
|
||||
return FtpOk;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FtpLibrary::State FtpLibrary::ReadBinary(void *buf, int max, FtpConnection *connection, int &length)
|
||||
{
|
||||
if (connection->direction != FtpConnection::Download)
|
||||
return FtpError;
|
||||
|
||||
FTP_PROPAGATE_ERROR__(WaitSocket(connection))
|
||||
length = net_read(connection->handle, buf, max);
|
||||
if (length == -1)
|
||||
return FtpError;
|
||||
|
||||
DataReadCallback(connection);
|
||||
return FtpOk;
|
||||
}
|
||||
FtpLibrary::State FtpLibrary::WriteBinary(void *buf, int len, FtpConnection *connection)
|
||||
{
|
||||
if (connection->direction != FtpConnection::Upload)
|
||||
return FtpError;
|
||||
|
||||
FTP_PROPAGATE_ERROR__(WaitSocket(connection))
|
||||
if (net_write(connection->handle, buf, len) != len)
|
||||
return FtpError;
|
||||
|
||||
DataWriteCallback(connection);
|
||||
return FtpOk;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
FtpLibrary::State FtpLibrary::DataTransfer(const char *localfile, const char *path, AccessType type, TransferMode mode)
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
// Open local file or I/O stream.
|
||||
FILE *file;
|
||||
|
||||
if (localfile)
|
||||
{
|
||||
const char *access;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
case AccessDir:
|
||||
case AccessDirVerbose:
|
||||
case AccessFileRead:
|
||||
access = (mode == TransferBinary) ? "wb" : "w";
|
||||
break;
|
||||
|
||||
case AccessFileReadAppend:
|
||||
access = (mode == TransferBinary) ? "ab" : "a";
|
||||
break;
|
||||
|
||||
case AccessFileWriteAppend:
|
||||
case AccessFileWrite:
|
||||
access = (mode == TransferBinary) ? "rb" : "r";
|
||||
break;
|
||||
}
|
||||
|
||||
file = fopen(localfile, access);
|
||||
if (!file)
|
||||
__ERR__(__LOG_E__ << "Failed to open FTP output file.\n", FtpError)
|
||||
|
||||
if (type == AccessFileWriteAppend)
|
||||
if (fseek(file, offset, SEEK_SET))
|
||||
{
|
||||
fclose(file);
|
||||
__ERR__(__LOG_E__ << "Failed to seek in FTP file for transfer.\n", FtpError)
|
||||
}
|
||||
}
|
||||
else
|
||||
file = (type == AccessFileWrite || type == AccessFileWriteAppend) ? stdin : stdout;
|
||||
|
||||
// Create a new connection.
|
||||
FtpConnection *connection = CreateConnection(path, type, mode);
|
||||
if (!connection)
|
||||
{
|
||||
if (localfile)
|
||||
fclose(file);
|
||||
return FtpError;
|
||||
}
|
||||
|
||||
// Perform transfer.
|
||||
State retv = FtpOk;
|
||||
GS::Array <char> temp_buffer(ConnectionBufferSize);
|
||||
int length;
|
||||
|
||||
if ((type == AccessFileWrite) || (type == AccessFileWriteAppend))
|
||||
{
|
||||
while ((length = (int)fread(temp_buffer, 1, ConnectionBufferSize, file)) > 0)
|
||||
if (WriteBinary(temp_buffer, length, connection) != FtpOk)
|
||||
{
|
||||
retv = FtpError; // FTP write failed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((retv = ReadBinary(temp_buffer, ConnectionBufferSize, connection, length)) == FtpOk)
|
||||
if (!length || (fwrite(temp_buffer, 1, length, file) <= 0))
|
||||
break; // Done.
|
||||
}
|
||||
|
||||
// Flush file.
|
||||
fflush(file);
|
||||
if (localfile)
|
||||
fclose(file);
|
||||
|
||||
CloseConnection(connection);
|
||||
return retv;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FtpLibrary::State FtpLibrary::Download(const char *file, const char *path, TransferMode mode, int _offset)
|
||||
{
|
||||
offset = _offset;
|
||||
if (!offset)
|
||||
return DataTransfer(file, path, AccessFileRead, mode);
|
||||
else return DataTransfer(file, path, AccessFileReadAppend, mode);
|
||||
}
|
||||
FtpLibrary::State FtpLibrary::Upload(const char *file, const char *path, TransferMode mode, int _offset)
|
||||
{
|
||||
offset = _offset;
|
||||
if (!offset)
|
||||
return DataTransfer(file, path, AccessFileWrite, mode);
|
||||
else return DataTransfer(file, path, AccessFileWriteAppend, mode);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------
|
||||
bool FtpLibrary::Quit()
|
||||
//------------------------------------
|
||||
{
|
||||
if (!master_connection.handle)
|
||||
return true;
|
||||
|
||||
bool r = FtpSendCmd("QUIT", '2');
|
||||
|
||||
net_close(master_connection.handle);
|
||||
master_connection.handle = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool FtpLibrary::DeleteFile(const char *path)
|
||||
{ return FtpSendCmd(String::Format("DELE %s", path).c_str(), '2'); }
|
||||
bool FtpLibrary::ChangeDirectory(const char *path)
|
||||
{ return FtpSendCmd(String::Format("CWD %s", path).c_str(), '2'); }
|
||||
bool FtpLibrary::UpDirectory()
|
||||
{ return FtpSendCmd("CDUP", '2'); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int FtpLibrary::GetFileSize(const char *path, TransferMode mode)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
int rs, sz = -1;
|
||||
if ( FtpSendCmd(String::Format("TYPE %c", mode).c_str(), '2') &&
|
||||
FtpSendCmd(String::Format("SIZE %s", path).c_str(), '2') &&
|
||||
(sscanf(response, "%d %d", &rs, &sz) == 2) )
|
||||
return sz;
|
||||
return -1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool FtpLibrary::Nlst(const char *outputfile, const char *path)
|
||||
//----------------------------------------------------------------------------
|
||||
{
|
||||
offset = 0;
|
||||
return DataTransfer(outputfile, path, FtpLibrary::AccessDir, FtpLibrary::TransferASCII) == FtpOk ? true : false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FtpLibrary::FtpLibrary()
|
||||
{
|
||||
#if __PLATFORM_WINDOWS__
|
||||
WSADATA wsa;
|
||||
if (WSAStartup(MAKEWORD(1, 1), &wsa))
|
||||
__LOG__ << "[!] (FTP) WINSOCK startup error.\n";
|
||||
#endif
|
||||
|
||||
connection_mode = ConnectionPORT;
|
||||
master_connection.AllocateBuffer();
|
||||
|
||||
//
|
||||
offset = 0;
|
||||
correctpasv = false;
|
||||
}
|
||||
FtpLibrary::~FtpLibrary()
|
||||
{ Quit(); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
int FtpLibrary::Site(const char *cmd)
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
if ((strlen(cmd) + 7) > sizeof(buf)) return 0;
|
||||
sprintf(buf,"SITE %s",cmd);
|
||||
if (!FtpSendCmd(buf,'2',mp_ftphandle)) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int FtpLibrary::Raw(const char *cmd)
|
||||
{
|
||||
char buf[256];
|
||||
strncpy(buf, cmd, 256);
|
||||
if (!FtpSendCmd(buf,'2',mp_ftphandle)) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int FtpLibrary::SysType(char *buf, int max)
|
||||
{
|
||||
int l = max;
|
||||
char *b = buf;
|
||||
char *s;
|
||||
if (!FtpSendCmd("SYST",'2',mp_ftphandle)) return 0;
|
||||
s = &mp_ftphandle->response[4];
|
||||
while ((--l) && (*s != ' ')) *b++ = *s++;
|
||||
*b++ = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
int FtpLibrary::Mkdir(const char *path)
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
if ((strlen(path) + 6) > sizeof(buf)) return 0;
|
||||
sprintf(buf,"MKD %s",path);
|
||||
if (!FtpSendCmd(buf,'2', mp_ftphandle)) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int FtpLibrary::Rmdir(const char *path)
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
if ((strlen(path) + 6) > sizeof(buf)) return 0;
|
||||
sprintf(buf,"RMD %s",path);
|
||||
if (!FtpSendCmd(buf,'2',mp_ftphandle)) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int FtpLibrary::Pwd(char *path, int max)
|
||||
{
|
||||
int l = max;
|
||||
char *b = path;
|
||||
char *s;
|
||||
|
||||
if (!FtpSendCmd("PWD",'2',mp_ftphandle)) return 0;
|
||||
s = strchr(mp_ftphandle->response, '"');
|
||||
if (s == NULL) return 0;
|
||||
s++;
|
||||
while ((--l) && (*s) && (*s != '"')) *b++ = *s++;
|
||||
*b++ = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
int FtpLibrary::Dir(const char *outputfile, const char *path)
|
||||
{
|
||||
mp_ftphandle->offset = 0;
|
||||
return FtpXfer(outputfile, path, mp_ftphandle, FtpLibrary::dirverbose, FtpLibrary::ascii);
|
||||
}
|
||||
|
||||
int FtpLibrary::ModDate(const char *path, char *dt, int max)
|
||||
{
|
||||
char buf[256];
|
||||
int rv = 1;
|
||||
|
||||
if ((strlen(path) + 7) > sizeof(buf)) return 0;
|
||||
sprintf(buf,"MDTM %s",path);
|
||||
if (!FtpSendCmd(buf,'2',mp_ftphandle)) rv = 0;
|
||||
else strncpy(dt, &mp_ftphandle->response[4], max);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int FtpLibrary::Rename(const char *src, const char *dst)
|
||||
{
|
||||
char cmd[256];
|
||||
|
||||
if (((strlen(src) + 7) > sizeof(cmd)) || ((strlen(dst) + 7) > sizeof(cmd))) return 0;
|
||||
sprintf(cmd,"RNFR %s",src);
|
||||
if (!FtpSendCmd(cmd,'3',mp_ftphandle)) return 0;
|
||||
sprintf(cmd,"RNTO %s",dst);
|
||||
if (!FtpSendCmd(cmd,'2',mp_ftphandle)) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void FtpLibrary::SetConnmode(connmode mode)
|
||||
{
|
||||
mp_ftphandle->cmode = mode;
|
||||
}
|
||||
|
||||
ftphandle* FtpLibrary::RawOpen(const char *path, accesstype type, transfermode mode)
|
||||
{
|
||||
int ret;
|
||||
ftphandle* datahandle;
|
||||
ret = CreateConnection(path, type, mode, mp_ftphandle, &datahandle);
|
||||
if (ret) return datahandle;
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
int FtpLibrary::RawClose(ftphandle* handle)
|
||||
{
|
||||
return FtpClose(handle);
|
||||
}
|
||||
|
||||
int FtpLibrary::RawWrite(void* buf, int len, ftphandle* handle)
|
||||
{
|
||||
return FtpWrite(buf, len, handle);
|
||||
}
|
||||
|
||||
int FtpLibrary::RawRead(void* buf, int max, ftphandle* handle)
|
||||
{
|
||||
return FtpRead(buf, max, handle);
|
||||
}
|
||||
*/
|
||||
59
include/platform/filesystem/io_base.cpp
Normal file
59
include/platform/filesystem/io_base.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "filesystem/io_base.h"
|
||||
#include "filesystem/io_handle.h"
|
||||
#include "memory/nauto_ptr.h"
|
||||
#include "nstring/nstring.h"
|
||||
#include "hash/nsha1.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using GS::String;
|
||||
using namespace GS::IO;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Base::FileLoad(const char *uri, GS::Array <char> &buffer)
|
||||
{
|
||||
AutoPtr <Handle> h(Open(uri));
|
||||
if (h.IsNull())
|
||||
return false;
|
||||
|
||||
size_t size = h->GetSize();
|
||||
if (!buffer.Allocate(size))
|
||||
return false;
|
||||
|
||||
return asbool(h->Read(buffer.c_ptr(), size) == size);
|
||||
}
|
||||
bool Base::FileSave(const char *uri, const GS::Array <char> &buffer)
|
||||
{
|
||||
AutoPtr <Handle> h(Open(uri, ModeWrite));
|
||||
if (h.IsNull())
|
||||
return false;
|
||||
|
||||
return asbool(h->Write(buffer.c_ptr(), buffer.GetSize()) == buffer.GetSize());
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Base::Exists(const char *uri)
|
||||
{
|
||||
AutoPtr <Handle> h(Open(uri, ModeRead));
|
||||
return h.IsValid();
|
||||
}
|
||||
String Base::Hash(const char *uri)
|
||||
{
|
||||
Array <char> data;
|
||||
return FileLoad(uri, data) ? SHA1::ComputeHexa(data) : String();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
String Base::MapToAbsolute(const char *uri) const
|
||||
{ return String(uri); }
|
||||
String Base::MapToRelative(const char *path) const
|
||||
{ return String(path); }
|
||||
//------------------------------------------------------------------------------
|
||||
130
include/platform/filesystem/io_buffer.cpp
Normal file
130
include/platform/filesystem/io_buffer.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "filesystem/io_buffer.h"
|
||||
#include "log/log.h"
|
||||
#include "ntypes.h"
|
||||
|
||||
using namespace GS::IO;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uint Buffer::GetCaps() const { return io->GetCaps(); }
|
||||
|
||||
Handle *Buffer::Open(const char *path, Mode mode)
|
||||
{
|
||||
AutoPtr <Handle> io_h(io->Open(path, mode));
|
||||
if (io_h.IsNull())
|
||||
return NULL;
|
||||
|
||||
AutoPtr <BufferHandle> b_h(new BufferHandle(this, io_h));
|
||||
if (b_h.IsNull())
|
||||
return NULL;
|
||||
|
||||
if (!b_h->read_buffer.buffer.Allocate(read_buffer_size))
|
||||
return NULL;
|
||||
|
||||
b_h->size = io_h->GetSize();
|
||||
|
||||
io_h.Detach();
|
||||
return b_h.Detach();
|
||||
}
|
||||
void Buffer::Close(Handle *h)
|
||||
{
|
||||
if (BufferHandle *b_h = (BufferHandle *)h)
|
||||
b_h->handle = NULL;
|
||||
}
|
||||
|
||||
bool Buffer::Delete(const char *path) { return io->Delete(path); }
|
||||
|
||||
size_t Buffer::Tell(Handle *h) { return ((BufferHandle *)h)->pos; }
|
||||
size_t Buffer::Seek(Handle *h, ptrdiff_t offset, SeekRef seek)
|
||||
{
|
||||
if (BufferHandle *c_h = (BufferHandle *)h)
|
||||
{
|
||||
switch (seek)
|
||||
{
|
||||
case SeekStart:
|
||||
c_h->pos = Types::Clamp <ptrdiff_t> (offset, 0, c_h->size);
|
||||
break;
|
||||
case SeekCurrent:
|
||||
c_h->pos = Types::Clamp <ptrdiff_t> (c_h->pos + offset, 0, c_h->size);
|
||||
break;
|
||||
case SeekEnd:
|
||||
c_h->pos = Types::Clamp <ptrdiff_t> (c_h->size + offset, 0, c_h->size);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return size_t(-1);
|
||||
}
|
||||
size_t Buffer::Read(Handle *h, void *data, size_t size)
|
||||
{
|
||||
// __LOG_V__ << "Buffer::Read: size = " << size << ".\n";
|
||||
|
||||
size_t read_size = 0;
|
||||
if (BufferHandle *b_h = (BufferHandle *)h)
|
||||
{
|
||||
while (read_size < size)
|
||||
{
|
||||
ptrdiff_t buffer_pos = (b_h->pos + read_size) - b_h->read_buffer.start_pos;
|
||||
|
||||
if ((buffer_pos >= 0) && (buffer_pos < ptrdiff_t(b_h->read_buffer.usage)))
|
||||
{
|
||||
ptrdiff_t copy_size = Types::Min <ptrdiff_t> (b_h->read_buffer.usage - buffer_pos, size - read_size);
|
||||
Memory::Copy((char *)data + read_size, b_h->read_buffer.buffer.c_ptr() + buffer_pos, copy_size);
|
||||
// __LOG_V__ << "Buffer read: pos = " << buffer_pos << ", size = " << copy_size << ".\n";
|
||||
read_size += copy_size;
|
||||
}
|
||||
else // refill cache
|
||||
{
|
||||
b_h->read_buffer.start_pos = b_h->pos + read_size;
|
||||
if (b_h->read_buffer.start_pos >= b_h->size)
|
||||
{
|
||||
b_h->read_buffer.usage = 0;
|
||||
break; // EJ 01/05: Improves EOF performance for the OGG streaming interface which makes many out of bound calls.
|
||||
}
|
||||
|
||||
io->Seek(b_h->handle, b_h->read_buffer.start_pos, SeekStart);
|
||||
b_h->read_buffer.usage = io->Read(b_h->handle, b_h->read_buffer.buffer.c_ptr(), b_h->read_buffer.buffer.GetSize());
|
||||
// __LOG_V__ << "Buffer fill: pos = " << b_h->read_buffer.start_pos << ", size = " << b_h->read_buffer.usage << ".\n";
|
||||
if (b_h->read_buffer.usage == 0)
|
||||
break; // EOF
|
||||
}
|
||||
}
|
||||
b_h->pos += read_size;
|
||||
}
|
||||
return read_size;
|
||||
}
|
||||
size_t Buffer::Write(Handle *h, const void *data, size_t size)
|
||||
{
|
||||
if (BufferHandle *b_h = (BufferHandle *)h)
|
||||
{
|
||||
size_t write_size = io->Write(b_h->handle, data, size);
|
||||
b_h->pos += write_size;
|
||||
return write_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
GS::String Buffer::Hash(const char *path)
|
||||
{ return io->Hash(path); } // [EJ] Do not perform a FileLoad here, IO::Buffer is typically sitting in front of a slow IO backend which potentially optimizes hash transfer.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Buffer::MkDir(const char *path)
|
||||
{ return io->MkDir(path); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Buffer::Buffer(Base *base, size_t read_size, size_t write_size) : io(base)
|
||||
{
|
||||
read_buffer_size = Types::Clamp <size_t> (read_size, 0, Units::MB(16));
|
||||
write_buffer_size = Types::Clamp <size_t> (write_size, 0, Units::MB(16));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
280
include/platform/filesystem/io_cache.cpp
Normal file
280
include/platform/filesystem/io_cache.cpp
Normal file
@ -0,0 +1,280 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "filesystem/io_cache.h"
|
||||
#include "hash/nsha1.h"
|
||||
#include "platform.h"
|
||||
#include "log/log.h"
|
||||
#include "ntypes.h"
|
||||
|
||||
using namespace GS::IO;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
struct FreeEntry // should be in ReserveOnStore but local type on template is prohibited until C++0x
|
||||
{
|
||||
Cache::Entry *entry;
|
||||
int score;
|
||||
|
||||
FreeEntry(Cache::Entry *e, int s) : entry(e), score(s) {}
|
||||
|
||||
static int ComputeScore(const Cache::Entry *e, size_t request_size, const GS::Time &ctime)
|
||||
{
|
||||
int time_bonus = (int)(ctime - e->last_use).toSec();
|
||||
int size_bonus = e->size - request_size;
|
||||
|
||||
return time_bonus + size_bonus / 8;
|
||||
}
|
||||
static int CompareScore(FreeEntry *a, FreeEntry *b)
|
||||
{ return b->score - a->score; }
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
GS::String Cache::ReserveOnStore(size_t size)
|
||||
{
|
||||
String id = store.Reserve(size);
|
||||
if (!id.IsEmpty())
|
||||
return id;
|
||||
|
||||
// Build a list of reference free entries.
|
||||
Time ctime = Platform::Get().GetTime();
|
||||
|
||||
// No need to drop anything if the request can't fit anyway...
|
||||
size_t total_freeable_store = 0;
|
||||
ListForeachPtr(Entry *, e, entries)
|
||||
if (e->refc == 0)
|
||||
total_freeable_store += e->size;
|
||||
|
||||
if (size > (store.GetFreeStore() + total_freeable_store))
|
||||
return "";
|
||||
|
||||
// Drop entries until the request fits in the store.
|
||||
List <FreeEntry *> free_entries;
|
||||
ListForeachPtr(Entry *, e, entries)
|
||||
if (e->refc == 0)
|
||||
free_entries.Add(new FreeEntry(e, FreeEntry::ComputeScore(e, size, ctime)));
|
||||
|
||||
free_entries.MergeSort(FreeEntry::CompareScore);
|
||||
|
||||
ListForeachPtr(FreeEntry *, e, free_entries)
|
||||
{
|
||||
__LOG_V__ << "IO::Cache: Disposing of cache entry '" << e->entry->path << "' (score: " << e->score << ").\n";
|
||||
|
||||
DeleteCacheEntry(e->entry);
|
||||
|
||||
id = store.Reserve(size);
|
||||
if (!id.IsEmpty())
|
||||
break;
|
||||
}
|
||||
|
||||
ListDeleteAllPtr(FreeEntry *, free_entries)
|
||||
|
||||
store.Save();
|
||||
return id;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Cache::Entry *Cache::GetCacheEntry(const char *path) const
|
||||
{
|
||||
ListForeachPtr(Entry *, entry, entries)
|
||||
if (entry->path == path)
|
||||
return entry;
|
||||
return NULL;
|
||||
}
|
||||
Cache::Entry *Cache::CreateCacheEntry(const char *path)
|
||||
{
|
||||
__LOG_V__ << "Create cache entry for '" << path << "'.\n";
|
||||
|
||||
Array <char> data;
|
||||
if (!io->FileLoad(path, data))
|
||||
return NULL;
|
||||
|
||||
AutoPtr <Entry> entry(new Entry);
|
||||
if (entry.IsNull())
|
||||
return NULL;
|
||||
|
||||
entry->path = path;
|
||||
entry->id = ReserveOnStore(data.GetSize());
|
||||
if (entry->id.IsEmpty())
|
||||
return NULL; // store full
|
||||
|
||||
Entry *e = entry.Detach();
|
||||
entries.Add(e);
|
||||
|
||||
return UpdateCacheEntry(e, &data) ? e : NULL;
|
||||
}
|
||||
bool Cache::UpdateCacheEntry(Entry *entry, GS::Array <char> *preloaded_data)
|
||||
{
|
||||
__LOG_V__ << "Update cache entry for '" << entry->path << "'.\n";
|
||||
|
||||
Array <char> data;
|
||||
if (preloaded_data)
|
||||
data.Transfer(*preloaded_data);
|
||||
else
|
||||
if (!io->FileLoad(entry->path, data))
|
||||
return false;
|
||||
|
||||
// Check current store entry size.
|
||||
if (store.GetEntrySize(entry->id) != data.GetSize())
|
||||
{
|
||||
store.Free(entry->id);
|
||||
entry->id = ReserveOnStore(data.GetSize());
|
||||
|
||||
if (entry->id.IsEmpty())
|
||||
return false; // store is full
|
||||
}
|
||||
|
||||
// Update store data.
|
||||
if (!store.Store(entry->id, data.c_ptr(), data.GetSize(), entry->path))
|
||||
return false;
|
||||
store.Save();
|
||||
|
||||
entry->hash = SHA1::ComputeHexa(data);
|
||||
entry->size = data.GetSize();
|
||||
return true;
|
||||
}
|
||||
bool Cache::DeleteCacheEntry(Entry *entry)
|
||||
{
|
||||
if (entry->refc > 0)
|
||||
return false;
|
||||
|
||||
store.Free(entry->id);
|
||||
store.Save();
|
||||
|
||||
return entries.Remove(entry);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uint Cache::GetCaps() const { return io->GetCaps(); }
|
||||
|
||||
Handle *Cache::Open(const char *path, Mode mode)
|
||||
{
|
||||
if (mode == ModeRead)
|
||||
{
|
||||
Threading::MutexLock lock(&mutex);
|
||||
|
||||
// Update cache.
|
||||
Entry *entry = GetCacheEntry(path);
|
||||
|
||||
if (entry)
|
||||
{
|
||||
__LOG_V__ << "Entry match for '" << path << "'.\n";
|
||||
|
||||
if (entry->hash != io->Hash(path))
|
||||
{
|
||||
__LOG_V__ << "Hash mismatch for '" << path << "'.\n";
|
||||
|
||||
if (entry->refc > 0)
|
||||
__LOG_W__ << "IO::Cache: Support file '" << entry->path << "' has changed but its cached version is in use and cannot be updated.\n";
|
||||
else
|
||||
{
|
||||
if (!UpdateCacheEntry(entry)) // contention risk here due to the mutex lock and a potentially long update (eg. networked fs)
|
||||
DeleteCacheEntry(entry);
|
||||
|
||||
// Check for a match in updated cache.
|
||||
entry = GetCacheEntry(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
entry = CreateCacheEntry(path);
|
||||
|
||||
// Return handler to store fs.
|
||||
if (entry)
|
||||
{
|
||||
__LOG_V__ << "Opening '" << path << "' from cache.\n";
|
||||
|
||||
entry->last_use = Platform::Get().GetTime();
|
||||
entry->refc++;
|
||||
|
||||
return new CacheHandle(this, path, store.GetIO()->Open(entry->id, mode));
|
||||
}
|
||||
}
|
||||
|
||||
// Direct access to the underlying fs.
|
||||
return io->Open(path, mode);
|
||||
}
|
||||
void Cache::Close(Handle *h)
|
||||
{
|
||||
if (CacheHandle *c_h = (CacheHandle *)h)
|
||||
{
|
||||
Threading::MutexLock lock(&mutex);
|
||||
|
||||
if (Entry *entry = GetCacheEntry(c_h->path))
|
||||
entry->refc--;
|
||||
c_h->handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool Cache::Delete(const char *path)
|
||||
{
|
||||
/*
|
||||
[EJ] Minor synchronization issue warning.
|
||||
|
||||
If a cached handle is already in use and the support fs file is deleted
|
||||
the cached handle will remain valid. Further open requests will then
|
||||
unexpectedly succeed as long as a single cached handler remains open.
|
||||
|
||||
The correct fix would be to prevent deleting a support file as long as
|
||||
a cached entry with a non-zero reference count exists for it.
|
||||
*/
|
||||
return io->Delete(path);
|
||||
}
|
||||
|
||||
size_t Cache::Tell(Handle *h)
|
||||
{ return ((CacheHandle *)h)->handle->Tell(); }
|
||||
size_t Cache::Seek(Handle *h, ptrdiff_t offset, SeekRef seek)
|
||||
{ return ((CacheHandle *)h)->handle->Seek(offset, seek); }
|
||||
|
||||
size_t Cache::Read(Handle *h, void *data, size_t size)
|
||||
{ return ((CacheHandle *)h)->handle->Read(data, size); }
|
||||
size_t Cache::Write(Handle *h, const void *data, size_t size)
|
||||
{ return ((CacheHandle *)h)->handle->Write(data, size); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Cache::SynchronizeWithStore(const char *store_path)
|
||||
{
|
||||
if (!store.Load(store_path))
|
||||
return false;
|
||||
|
||||
entries.Clear();
|
||||
|
||||
__LOG_H__ << "IO::Cache: Synchronizing with store.\n";
|
||||
|
||||
ListForeachPtr(DataStore::Entry *, e, store.GetEntries())
|
||||
{
|
||||
Entry *entry = new Entry;
|
||||
|
||||
entry->id = e->id;
|
||||
entry->size = e->size;
|
||||
entry->path = e->user;
|
||||
entry->hash = store.GetIO()->Hash(entry->id);
|
||||
|
||||
entries.Add(entry);
|
||||
}
|
||||
|
||||
__LOG__ << "Done, " << entries.GetCount() << " entries synchronized.\n";
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Cache::MkDir(const char *path)
|
||||
{ return io->MkDir(path); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Cache::Cache(Base *base, Base *store_io, size_t store_size) : io(base), store(store_io, store_size) {}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CacheHandle::~CacheHandle()
|
||||
{ GetIOSystem()->Close(this); }
|
||||
//-----------------------------------------------------------------------------
|
||||
137
include/platform/filesystem/io_cfile.cpp
Normal file
137
include/platform/filesystem/io_cfile.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#if __PLATFORM_POSIX__
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#elif __PLATFORM_WINDOWS__
|
||||
#include <direct.h>
|
||||
#endif
|
||||
#include "filesystem/io_cfile.h"
|
||||
#include "memory/nauto_ptr.h"
|
||||
|
||||
using GS::String;
|
||||
using namespace GS::IO;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CFile::SetRootPath(const char *_root)
|
||||
{ root = _root; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uint CFile::GetCaps() const
|
||||
{
|
||||
uint flags = CanRead | CanWrite | CanSeek | CanMkDir;
|
||||
#ifndef __PLATFORM_WINDOWS__
|
||||
flags |= IsCaseSensitive;
|
||||
#endif
|
||||
return flags;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
String CFile::MapToAbsolute(const char *uri) const
|
||||
{
|
||||
if (!root.IsEmpty())
|
||||
return root + "/" + uri;
|
||||
return String(uri);
|
||||
}
|
||||
String CFile::MapToRelative(const char *path) const
|
||||
{
|
||||
String _path(path);
|
||||
if (!root.IsEmpty() && _path.StartsWith(root, GetCaps() & IsCaseSensitive ? String::CaseSensitive : String::CaseInsensitive))
|
||||
return _path.Mid(root.Len());
|
||||
return _path;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Handle *CFile::Open(const char *path, Mode mode)
|
||||
{
|
||||
String _path(root.IsEmpty() ? path : (root + "/" + path).c_str()),
|
||||
_access(mode == ModeRead ? "rb" : "wb");
|
||||
|
||||
AutoPtr <CFileHandle> h(new CFileHandle(this));
|
||||
#if __PLATFORM_WINDOWS__
|
||||
if (h->file = _wfopen((const wchar_t *)_path.toUcs2().c_ptr(), (const wchar_t *)_access.toUcs2().c_ptr()))
|
||||
return h.Detach();
|
||||
#else
|
||||
if ((h->file = fopen(_path, _access)) != NULL)
|
||||
return h.Detach();
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
void CFile::Close(Handle *h)
|
||||
{
|
||||
if (CFileHandle *ch = (CFileHandle *)h)
|
||||
if (ch->file)
|
||||
fclose(ch->file);
|
||||
}
|
||||
|
||||
bool CFile::Delete(const char *uri)
|
||||
{ return asbool(unlink(root + "/" + uri) == 0); }
|
||||
|
||||
size_t CFile::Seek(Handle *h, ptrdiff_t offset, SeekRef ref)
|
||||
{
|
||||
if (CFileHandle *ch = (CFileHandle *)h)
|
||||
if (ch->file)
|
||||
{
|
||||
int c_seek[] = { SEEK_SET, SEEK_CUR, SEEK_END };
|
||||
return fseek(ch->file, offset, c_seek[ref]);
|
||||
}
|
||||
return (size_t)-1;
|
||||
}
|
||||
size_t CFile::Tell(Handle *h)
|
||||
{
|
||||
if (CFileHandle *ch = (CFileHandle *)h)
|
||||
if (ch->file)
|
||||
return ftell(ch->file);
|
||||
return (size_t)-1;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
size_t CFile::Read(Handle *h, void *b, size_t size)
|
||||
{
|
||||
if (CFileHandle *ch = (CFileHandle *)h)
|
||||
if (ch->file)
|
||||
return fread(b, 1, size, ch->file);
|
||||
return 0;
|
||||
}
|
||||
size_t CFile::Write(Handle *h, const void *b, size_t size)
|
||||
{
|
||||
if (CFileHandle *ch = (CFileHandle *)h)
|
||||
if (ch->file)
|
||||
return fwrite(b, size, 1, ch->file) * size;
|
||||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool CFile::MkDir(const char *path)
|
||||
{
|
||||
String _path(root.IsEmpty() ? path : (root + "/" + path).c_str());
|
||||
|
||||
bool r = false;
|
||||
#if __PLATFORM_WINDOWS__
|
||||
r = _wmkdir((const wchar_t *)_path.toUcs2().c_ptr()) == 0;
|
||||
#else
|
||||
r = mkdir(path, 01777) == 0;
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
CFile::CFile(const char *root_path)
|
||||
{ SetRootPath(root_path); }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
CFileHandle::CFileHandle(Base *io) : Handle(io)
|
||||
{ file = NULL; }
|
||||
CFileHandle::~CFileHandle()
|
||||
{ GetIOSystem()->Close(this); }
|
||||
//------------------------------------------------------------------------------
|
||||
173
include/platform/filesystem/io_crypto.cpp
Normal file
173
include/platform/filesystem/io_crypto.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "filesystem/io_crypto.h"
|
||||
|
||||
using namespace GS::IO;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uint Crypto::GetCaps() const
|
||||
{ return wrapped_io->GetCaps(); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Crypto::Encrypt(GS::Array <char> &data)
|
||||
{
|
||||
size_t len = key.Len();
|
||||
for (size_t n = 0; n < data.GetSize(); ++n)
|
||||
data[(int)n] = data[(int)n] ^ key[(int)(n % len)];
|
||||
}
|
||||
void Crypto::Decrypt(GS::Array <char> &data)
|
||||
{
|
||||
size_t len = key.Len();
|
||||
for (size_t n = 0; n < data.GetSize(); ++n)
|
||||
data[(int)n] = data[(int)n] ^ key[(int)(n % len)];
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Handle *Crypto::Open(const char *path, Mode mode)
|
||||
{
|
||||
/*
|
||||
When opening a file in read mode, the wrapped io file is decrypted and
|
||||
stored in the cached io file system for further access.
|
||||
When opening a file in write mode, the file is first created in clear
|
||||
on the cached io then encrypted and committed to the wrapped io.
|
||||
*/
|
||||
Handle *h = NULL;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case ModeRead:
|
||||
{
|
||||
// Load wrapped IO file.
|
||||
AutoPtr <Handle> _h(wrapped_io->Open(path, mode));
|
||||
if (_h.IsNull())
|
||||
break;
|
||||
|
||||
size_t size = _h->GetSize();
|
||||
Array <char> data(size);
|
||||
if (data.IsNull())
|
||||
break;
|
||||
if (_h->Read(data.c_ptr(), size) != size)
|
||||
break;
|
||||
|
||||
// Decrypt buffer.
|
||||
Decrypt(data);
|
||||
|
||||
// Write decrypted content to cache IO.
|
||||
if ((h = cache_io->Open(path, ModeWrite)) != NULL)
|
||||
h->Write(data.c_ptr(), size);
|
||||
_safe_delete(h);
|
||||
|
||||
h = cache_io->Open(path, mode);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModeWrite:
|
||||
h = cache_io->Open(path, mode);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
return h ? new CryptoHandle(this, h, path, mode) : NULL;
|
||||
}
|
||||
void Crypto::Close(Handle *_h)
|
||||
{
|
||||
if (CryptoHandle *h = (CryptoHandle *)_h)
|
||||
{
|
||||
h->cached_h = NULL;
|
||||
|
||||
switch (h->io_mode)
|
||||
{
|
||||
case ModeRead:
|
||||
cache_io->Delete(h->path);
|
||||
break;
|
||||
|
||||
case ModeWrite:
|
||||
{
|
||||
// Retrieve the whole cached file content and drop it from the cache IO.
|
||||
h->cached_h = cache_io->Open(h->path);
|
||||
|
||||
size_t size = h->cached_h->GetSize();
|
||||
Array <char> data(size);
|
||||
|
||||
if (data.IsValid())
|
||||
h->cached_h->Read(data.c_ptr(), size);
|
||||
|
||||
h->cached_h = NULL;
|
||||
cache_io->Delete(h->path);
|
||||
|
||||
// Encrypt buffer.
|
||||
Encrypt(data);
|
||||
|
||||
// Commit file to the wrapped IO.
|
||||
AutoPtr <Handle> _h(wrapped_io->Open(h->path, ModeWrite));
|
||||
if (_h.IsValid())
|
||||
_h->Write(data.c_ptr(), size);
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Crypto::Delete(const char *path)
|
||||
{ return wrapped_io->Delete(path); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
size_t Crypto::Tell(Handle *_h)
|
||||
{
|
||||
if (CryptoHandle *h = (CryptoHandle *)_h)
|
||||
return h->cached_h->Tell();
|
||||
return (size_t)-1;
|
||||
}
|
||||
size_t Crypto::Seek(Handle *_h, ptrdiff_t offset, SeekRef seek)
|
||||
{
|
||||
if (CryptoHandle *h = (CryptoHandle *)_h)
|
||||
return h->cached_h->Seek(offset, seek);
|
||||
return (size_t)-1;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
size_t Crypto::Read(Handle *_h, void *p, size_t s)
|
||||
{
|
||||
if (CryptoHandle *h = (CryptoHandle *)_h)
|
||||
return h->cached_h->Read(p, s);
|
||||
return 0;
|
||||
}
|
||||
size_t Crypto::Write(Handle *_h, const void *p, size_t s)
|
||||
{
|
||||
if (CryptoHandle *h = (CryptoHandle *)_h)
|
||||
return h->cached_h->Write(p, s);
|
||||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Crypto::MkDir(const char *path)
|
||||
{ return wrapped_io->MkDir(path); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Crypto::Crypto(Base *_io, const char *_key) : wrapped_io(_io)
|
||||
{
|
||||
cache_io = new Memory;
|
||||
key = _key;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
CryptoHandle::CryptoHandle(Base *io, Handle *h, const char *_path, Mode mode) : Handle(io), cached_h(h), path(_path), io_mode(mode)
|
||||
{}
|
||||
CryptoHandle::~CryptoHandle()
|
||||
{ GetIOSystem()->Close(this); }
|
||||
//------------------------------------------------------------------------------
|
||||
141
include/platform/filesystem/io_dispatcher.cpp
Normal file
141
include/platform/filesystem/io_dispatcher.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#if __PLATFORM_POSIX__
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "filesystem/io_dispatcher.h"
|
||||
#include "memory/nauto_ptr.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::IO;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Dispatcher::AddDispatch(Base *fs, const char *prefix)
|
||||
{
|
||||
if (prefix)
|
||||
{
|
||||
DispatchFS *d = new DispatchFS;
|
||||
if (!d)
|
||||
return false;
|
||||
|
||||
d->fs = fs;
|
||||
d->prefix = prefix;
|
||||
mounts.Add(d);
|
||||
}
|
||||
else
|
||||
roots.Add(fs);
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uint Dispatcher::GetCaps() const
|
||||
{
|
||||
uint flags = CanRead | CanWrite | CanSeek;
|
||||
#ifndef __PLATFORM_WINDOWS__
|
||||
flags |= IsCaseSensitive;
|
||||
#endif
|
||||
return flags;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Base *Dispatcher::Dispatch(String &uri, Mode mode)
|
||||
{
|
||||
ListForeachPtr(DispatchFS *, d, mounts)
|
||||
if (uri.StartsWith(d->prefix))
|
||||
{
|
||||
uri = uri.Mid(d->prefix.Len());
|
||||
return d->fs;
|
||||
}
|
||||
|
||||
// Root FS make no sense for write operations.
|
||||
if (mode == ModeRead)
|
||||
ListForeachPtr(Base *, d, roots)
|
||||
if (d->Exists(uri))
|
||||
return d;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Handle *Dispatcher::Open(const char *uri, Mode mode)
|
||||
{
|
||||
String _uri(uri);
|
||||
|
||||
Base *base = Dispatch(_uri, mode);
|
||||
if (!base)
|
||||
return NULL;
|
||||
|
||||
Handle *h = base->Open(_uri, mode);
|
||||
return h ? new DispatcherHandle(this, h) : NULL;
|
||||
}
|
||||
void Dispatcher::Close(Handle *h)
|
||||
{
|
||||
if (DispatcherHandle *dh = (DispatcherHandle *)h)
|
||||
dh->handle->GetIOSystem()->Close(dh->handle);
|
||||
}
|
||||
bool Dispatcher::Delete(const char *uri)
|
||||
{ return false; }
|
||||
size_t Dispatcher::Seek(Handle *h, ptrdiff_t offset, SeekRef ref)
|
||||
{
|
||||
if (DispatcherHandle *dh = (DispatcherHandle *)h)
|
||||
return dh->handle->GetIOSystem()->Seek(dh->handle, offset, ref);
|
||||
return (size_t)-1;
|
||||
}
|
||||
size_t Dispatcher::Tell(Handle *h)
|
||||
{
|
||||
if (DispatcherHandle *dh = (DispatcherHandle *)h)
|
||||
return dh->handle->GetIOSystem()->Tell(dh->handle);
|
||||
return (size_t)-1;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
size_t Dispatcher::Read(Handle *h, void *b, size_t size)
|
||||
{
|
||||
if (DispatcherHandle *dh = (DispatcherHandle *)h)
|
||||
return dh->handle->GetIOSystem()->Read(dh->handle, b, size);
|
||||
return 0;
|
||||
}
|
||||
size_t Dispatcher::Write(Handle *h, const void *b, size_t size)
|
||||
{
|
||||
if (DispatcherHandle *dh = (DispatcherHandle *)h)
|
||||
return dh->handle->GetIOSystem()->Write(dh->handle, b, size);
|
||||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Dispatcher::MkDir(const char *path)
|
||||
{
|
||||
String _path(path);
|
||||
if (Base *base = Dispatch(_path, ModeWrite))
|
||||
return base->MkDir(_path);
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
String Dispatcher::Hash(const char *uri)
|
||||
{
|
||||
String _uri(uri);
|
||||
if (Base *base = Dispatch(_uri, ModeRead))
|
||||
return base->Hash(_uri);
|
||||
return String();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
DispatcherHandle::DispatcherHandle(Base *io, Handle *h) : Handle(io), handle(h)
|
||||
{}
|
||||
DispatcherHandle::~DispatcherHandle()
|
||||
{ GetIOSystem()->Close(this); }
|
||||
//------------------------------------------------------------------------------
|
||||
58
include/platform/filesystem/io_handle.cpp
Normal file
58
include/platform/filesystem/io_handle.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include "filesystem/io_handle.h"
|
||||
#include "filesystem/io_base.h"
|
||||
|
||||
using namespace GS::IO;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
size_t Handle::GetSize()
|
||||
{
|
||||
size_t p = Tell();
|
||||
Seek(0, Base::SeekEnd);
|
||||
size_t s = Tell();
|
||||
Seek(p, Base::SeekStart);
|
||||
return s;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Handle::IsEOF()
|
||||
{ return Tell() >= GetSize(); }
|
||||
size_t Handle::Rewind()
|
||||
{ return Seek(0, Base::SeekStart); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
size_t Handle::Tell()
|
||||
{ return io_sys.IsValid() ? io_sys->Tell(this) : 0; }
|
||||
size_t Handle::Seek(ptrdiff_t offset, Base::SeekRef seek_ref)
|
||||
{ return io_sys.IsValid() ? io_sys->Seek(this, offset, seek_ref) : 0; }
|
||||
|
||||
size_t Handle::Read(void *p, size_t size)
|
||||
{ return io_sys.IsValid() ? io_sys->Read(this, p, size) : 0; }
|
||||
size_t Handle::Write(const void *p, size_t size)
|
||||
{ return io_sys.IsValid() ? io_sys->Write(this, p, size) : 0; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Handle &Handle::operator << (const char *s)
|
||||
{
|
||||
if (s)
|
||||
Write(s, strlen(s));
|
||||
return *this;
|
||||
}
|
||||
Handle &Handle::operator << (char *s)
|
||||
{ return *this << ((const char *)s); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Handle::Handle(Base *io) : io_sys(io) {}
|
||||
Handle::~Handle() {}
|
||||
//------------------------------------------------------------------------------
|
||||
80
include/platform/filesystem/io_handle_segment.cpp
Normal file
80
include/platform/filesystem/io_handle_segment.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "filesystem/io_handle_segment.h"
|
||||
|
||||
using namespace GS::IO;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
size_t HandleSegment::GetSize()
|
||||
{ return size; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
size_t HandleSegment::Tell()
|
||||
{ return cursor; }
|
||||
size_t HandleSegment::Seek(ptrdiff_t offset, Base::SeekRef ref)
|
||||
{
|
||||
switch (ref)
|
||||
{
|
||||
case Base::SeekStart:
|
||||
cursor = offset;
|
||||
break;
|
||||
case Base::SeekCurrent:
|
||||
cursor += offset;
|
||||
break;
|
||||
case Base::SeekEnd:
|
||||
cursor = size - offset;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cursor > size)
|
||||
{
|
||||
cursor = 0;
|
||||
return (size_t)-1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
IO segment must always restore the original handle position and act as
|
||||
transparently as possible.
|
||||
*/
|
||||
size_t HandleSegment::Read(void *b, size_t s)
|
||||
{
|
||||
size_t o = 0;
|
||||
|
||||
size_t t = handle->Tell();
|
||||
|
||||
if (!handle->Seek(offset + cursor, Base::SeekStart))
|
||||
{
|
||||
if (s > (size - cursor))
|
||||
s = size - cursor;
|
||||
o = handle->Read(b, s);
|
||||
cursor += o;
|
||||
}
|
||||
handle->Seek(t, Base::SeekStart);
|
||||
|
||||
return o;
|
||||
}
|
||||
size_t HandleSegment::Write(const void *b, size_t s)
|
||||
{
|
||||
size_t o = 0;
|
||||
|
||||
size_t t = handle->Tell();
|
||||
if (!handle->Seek(offset + cursor, Base::SeekStart))
|
||||
{
|
||||
o = handle->Write(b, s);
|
||||
cursor += o;
|
||||
}
|
||||
handle->Seek(t, Base::SeekStart);
|
||||
|
||||
return o;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
132
include/platform/filesystem/io_memory.cpp
Normal file
132
include/platform/filesystem/io_memory.cpp
Normal file
@ -0,0 +1,132 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "filesystem/io_memory.h"
|
||||
|
||||
using namespace GS::IO;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uint Memory::GetCaps() const
|
||||
{ return CanRead | CanWrite | CanSeek| IsCaseSensitive; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Handle *Memory::Open(const char *uri, Mode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case ModeRead:
|
||||
ListForeachPtr(MemoryFile *, f, fat)
|
||||
if (f->uri == uri)
|
||||
return new MemoryHandle(this, f, mode);
|
||||
break;
|
||||
|
||||
case ModeWrite:
|
||||
{
|
||||
MemoryFile *f_entry = NULL;
|
||||
ListForeachPtr(MemoryFile *, f, fat)
|
||||
if (f->uri == uri)
|
||||
{
|
||||
f_entry = f;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!f_entry)
|
||||
fat.Add(f_entry = new MemoryFile(uri));
|
||||
|
||||
return f_entry ? new MemoryHandle(this, f_entry, mode) : NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void Memory::Close(Handle *h)
|
||||
{ /* Nothing to be done. */ }
|
||||
|
||||
bool Memory::Delete(const char *uri)
|
||||
{
|
||||
ListForeachPtr(MemoryFile *, f, fat)
|
||||
if (f->uri == uri)
|
||||
return fat.Remove(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t Memory::Tell(Handle *h)
|
||||
{
|
||||
if (MemoryHandle *_h = (MemoryHandle *)h)
|
||||
if (_h->file)
|
||||
return _h->cursor;
|
||||
return (size_t)-1;
|
||||
}
|
||||
size_t Memory::Seek(Handle *h, ptrdiff_t offset, SeekRef seek_ref)
|
||||
{
|
||||
if (MemoryHandle *_h = (MemoryHandle *)h)
|
||||
if (_h->file)
|
||||
{
|
||||
switch (seek_ref)
|
||||
{
|
||||
case SeekStart:
|
||||
_h->cursor = Types::Clamp <ptrdiff_t> (offset, 0, _h->file->size);
|
||||
break;
|
||||
case SeekCurrent:
|
||||
_h->cursor = Types::Clamp <ptrdiff_t> (_h->cursor + offset, 0, _h->file->size);
|
||||
break;
|
||||
case SeekEnd:
|
||||
_h->cursor = Types::Clamp <ptrdiff_t> (_h->file->size - offset, 0, _h->file->size);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (size_t)-1;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
size_t Memory::Read(Handle *h, void *ptr, size_t size)
|
||||
{
|
||||
size_t read_size = 0;
|
||||
if (MemoryHandle *_h = (MemoryHandle *)h)
|
||||
if (_h->file && (_h->mode == ModeRead))
|
||||
{
|
||||
read_size = Types::Min <ptrdiff_t> (size, _h->file->size - _h->cursor);
|
||||
GS::Memory::Copy(ptr, &_h->file->data[(int)_h->cursor], read_size);
|
||||
_h->cursor += read_size;
|
||||
}
|
||||
|
||||
return read_size;
|
||||
}
|
||||
size_t Memory::Write(Handle *h, const void *ptr, size_t size)
|
||||
{
|
||||
size_t write_size = 0;
|
||||
if (MemoryHandle *_h = (MemoryHandle *)h)
|
||||
if (_h->file && (_h->mode == ModeWrite))
|
||||
{
|
||||
size_t req_size = _h->cursor + size;
|
||||
if (req_size > _h->file->data.GetSize())
|
||||
if (!_h->file->data.Reallocate(req_size + 16384)) // required size + 16 kilobytes
|
||||
return 0;
|
||||
|
||||
GS::Memory::Copy(&_h->file->data[(int)_h->cursor], ptr, size);
|
||||
write_size = size;
|
||||
|
||||
_h->cursor += size;
|
||||
_h->file->size = Types::Max(_h->file->size, req_size);
|
||||
}
|
||||
|
||||
return write_size;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
MemoryHandle::MemoryHandle(Base *io, MemoryFile *_file, Mode _mode) : Handle(io), file(_file), cursor(0), mode(_mode)
|
||||
{}
|
||||
MemoryHandle::~MemoryHandle()
|
||||
{ GetIOSystem()->Close(this); }
|
||||
//------------------------------------------------------------------------------
|
||||
374
include/platform/hash/md5.cpp
Normal file
374
include/platform/hash/md5.cpp
Normal file
@ -0,0 +1,374 @@
|
||||
/*
|
||||
|
||||
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
L. Peter Deutsch
|
||||
ghost@aladdin.com
|
||||
|
||||
*/
|
||||
|
||||
/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
|
||||
|
||||
/*
|
||||
Independent implementation of MD5 (RFC 1321).
|
||||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||
text is available at
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
The code is derived from the text of the RFC, including the test suite
|
||||
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||
any code or documentation that is identified in the RFC as being
|
||||
copyrighted.
|
||||
|
||||
The original and principal author of md5.h is L. Peter Deutsch
|
||||
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||
that follows (in reverse chronological order):
|
||||
|
||||
2002-04-13 lpd Removed support for non-ANSI compilers; removed
|
||||
references to Ghostscript; clarified derivation from RFC 1321;
|
||||
now handles byte order either statically or dynamically.
|
||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
|
||||
added conditionalization for C++ compilation from Martin
|
||||
Purschke <purschke@bnl.gov>.
|
||||
1999-05-03 lpd Original version.
|
||||
*/
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include "hash/md5.h"
|
||||
#include "memory/endian.h"
|
||||
|
||||
using namespace GS::MD5;
|
||||
|
||||
|
||||
#define T_MASK ((md5_word_t)~0)
|
||||
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
|
||||
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
|
||||
#define T3 0x242070db
|
||||
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
|
||||
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
|
||||
#define T6 0x4787c62a
|
||||
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
|
||||
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
|
||||
#define T9 0x698098d8
|
||||
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
|
||||
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
|
||||
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
|
||||
#define T13 0x6b901122
|
||||
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
|
||||
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
|
||||
#define T16 0x49b40821
|
||||
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
|
||||
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
|
||||
#define T19 0x265e5a51
|
||||
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
|
||||
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
|
||||
#define T22 0x02441453
|
||||
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
|
||||
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
|
||||
#define T25 0x21e1cde6
|
||||
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
|
||||
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
|
||||
#define T28 0x455a14ed
|
||||
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
|
||||
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
|
||||
#define T31 0x676f02d9
|
||||
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
|
||||
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
|
||||
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
|
||||
#define T35 0x6d9d6122
|
||||
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
|
||||
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
|
||||
#define T38 0x4bdecfa9
|
||||
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
|
||||
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
|
||||
#define T41 0x289b7ec6
|
||||
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
|
||||
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
|
||||
#define T44 0x04881d05
|
||||
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
|
||||
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
|
||||
#define T47 0x1fa27cf8
|
||||
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
|
||||
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
|
||||
#define T50 0x432aff97
|
||||
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
|
||||
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
|
||||
#define T53 0x655b59c3
|
||||
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
|
||||
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
|
||||
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
|
||||
#define T57 0x6fa87e4f
|
||||
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
|
||||
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
|
||||
#define T60 0x4e0811a1
|
||||
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
|
||||
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
|
||||
#define T63 0x2ad7d2bb
|
||||
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Digest::Process(const md5_byte_t *data /*[64]*/)
|
||||
{
|
||||
md5_word_t a = abcd[0], b = abcd[1],
|
||||
c = abcd[2], d = abcd[3],
|
||||
t;
|
||||
|
||||
md5_word_t xbuf[16];
|
||||
const md5_word_t *X;
|
||||
|
||||
if (GS::Endian::GetHostConfiguration() == GS::Endian::Little)
|
||||
{
|
||||
/*
|
||||
On little-endian machines, we can process properly aligned
|
||||
data without copying it.
|
||||
*/
|
||||
if (!((data - (const md5_byte_t *)0) & 3))
|
||||
// Data are properly aligned.
|
||||
X = (const md5_word_t *)data;
|
||||
else
|
||||
{
|
||||
// Not aligned.
|
||||
memcpy(xbuf, data, 64);
|
||||
X = xbuf;
|
||||
}
|
||||
}
|
||||
else // Dynamic big-endian.
|
||||
{
|
||||
/*
|
||||
On big-endian machines, we must arrange the bytes in the
|
||||
right order.
|
||||
*/
|
||||
const md5_byte_t *xp = data;
|
||||
X = xbuf;
|
||||
for (int i = 0; i < 16; ++i, xp += 4)
|
||||
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
|
||||
}
|
||||
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
/* Round 1. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + F(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 7, T1);
|
||||
SET(d, a, b, c, 1, 12, T2);
|
||||
SET(c, d, a, b, 2, 17, T3);
|
||||
SET(b, c, d, a, 3, 22, T4);
|
||||
SET(a, b, c, d, 4, 7, T5);
|
||||
SET(d, a, b, c, 5, 12, T6);
|
||||
SET(c, d, a, b, 6, 17, T7);
|
||||
SET(b, c, d, a, 7, 22, T8);
|
||||
SET(a, b, c, d, 8, 7, T9);
|
||||
SET(d, a, b, c, 9, 12, T10);
|
||||
SET(c, d, a, b, 10, 17, T11);
|
||||
SET(b, c, d, a, 11, 22, T12);
|
||||
SET(a, b, c, d, 12, 7, T13);
|
||||
SET(d, a, b, c, 13, 12, T14);
|
||||
SET(c, d, a, b, 14, 17, T15);
|
||||
SET(b, c, d, a, 15, 22, T16);
|
||||
#undef SET
|
||||
|
||||
/* Round 2. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define _G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + _G(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 1, 5, T17);
|
||||
SET(d, a, b, c, 6, 9, T18);
|
||||
SET(c, d, a, b, 11, 14, T19);
|
||||
SET(b, c, d, a, 0, 20, T20);
|
||||
SET(a, b, c, d, 5, 5, T21);
|
||||
SET(d, a, b, c, 10, 9, T22);
|
||||
SET(c, d, a, b, 15, 14, T23);
|
||||
SET(b, c, d, a, 4, 20, T24);
|
||||
SET(a, b, c, d, 9, 5, T25);
|
||||
SET(d, a, b, c, 14, 9, T26);
|
||||
SET(c, d, a, b, 3, 14, T27);
|
||||
SET(b, c, d, a, 8, 20, T28);
|
||||
SET(a, b, c, d, 13, 5, T29);
|
||||
SET(d, a, b, c, 2, 9, T30);
|
||||
SET(c, d, a, b, 7, 14, T31);
|
||||
SET(b, c, d, a, 12, 20, T32);
|
||||
#undef SET
|
||||
|
||||
/* Round 3. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + H(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 5, 4, T33);
|
||||
SET(d, a, b, c, 8, 11, T34);
|
||||
SET(c, d, a, b, 11, 16, T35);
|
||||
SET(b, c, d, a, 14, 23, T36);
|
||||
SET(a, b, c, d, 1, 4, T37);
|
||||
SET(d, a, b, c, 4, 11, T38);
|
||||
SET(c, d, a, b, 7, 16, T39);
|
||||
SET(b, c, d, a, 10, 23, T40);
|
||||
SET(a, b, c, d, 13, 4, T41);
|
||||
SET(d, a, b, c, 0, 11, T42);
|
||||
SET(c, d, a, b, 3, 16, T43);
|
||||
SET(b, c, d, a, 6, 23, T44);
|
||||
SET(a, b, c, d, 9, 4, T45);
|
||||
SET(d, a, b, c, 12, 11, T46);
|
||||
SET(c, d, a, b, 15, 16, T47);
|
||||
SET(b, c, d, a, 2, 23, T48);
|
||||
#undef SET
|
||||
|
||||
/* Round 4. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + I(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 6, T49);
|
||||
SET(d, a, b, c, 7, 10, T50);
|
||||
SET(c, d, a, b, 14, 15, T51);
|
||||
SET(b, c, d, a, 5, 21, T52);
|
||||
SET(a, b, c, d, 12, 6, T53);
|
||||
SET(d, a, b, c, 3, 10, T54);
|
||||
SET(c, d, a, b, 10, 15, T55);
|
||||
SET(b, c, d, a, 1, 21, T56);
|
||||
SET(a, b, c, d, 8, 6, T57);
|
||||
SET(d, a, b, c, 15, 10, T58);
|
||||
SET(c, d, a, b, 6, 15, T59);
|
||||
SET(b, c, d, a, 13, 21, T60);
|
||||
SET(a, b, c, d, 4, 6, T61);
|
||||
SET(d, a, b, c, 11, 10, T62);
|
||||
SET(c, d, a, b, 2, 15, T63);
|
||||
SET(b, c, d, a, 9, 21, T64);
|
||||
#undef SET
|
||||
|
||||
/*
|
||||
Then perform the following additions. (That is increment each of the
|
||||
four registers by the value it had before this block was started.)
|
||||
*/
|
||||
abcd[0] += a;
|
||||
abcd[1] += b;
|
||||
abcd[2] += c;
|
||||
abcd[3] += d;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Digest::Reset()
|
||||
{
|
||||
count[0] = count[1] = 0;
|
||||
abcd[0] = 0x67452301;
|
||||
abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
|
||||
abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
|
||||
abcd[3] = 0x10325476;
|
||||
}
|
||||
void Digest::Append(const md5_byte_t *data, int nbytes)
|
||||
{
|
||||
const md5_byte_t *p = data;
|
||||
int left = nbytes,
|
||||
offset = (count[0] >> 3) & 63;
|
||||
md5_word_t nbits = (md5_word_t)(nbytes << 3);
|
||||
|
||||
if (nbytes <= 0)
|
||||
return;
|
||||
|
||||
// Update the message length.
|
||||
count[1] += nbytes >> 29;
|
||||
count[0] += nbits;
|
||||
if (count[0] < nbits)
|
||||
count[1]++;
|
||||
|
||||
// Process an initial partial block.
|
||||
if (offset)
|
||||
{
|
||||
int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
|
||||
|
||||
memcpy(buf + offset, p, copy);
|
||||
if (offset + copy < 64)
|
||||
return;
|
||||
|
||||
p += copy;
|
||||
left -= copy;
|
||||
Process(buf);
|
||||
}
|
||||
|
||||
// Process full blocks.
|
||||
for (; left >= 64; p += 64, left -= 64)
|
||||
Process(p);
|
||||
|
||||
// Process a final partial block.
|
||||
if (left)
|
||||
memcpy(buf, p, left);
|
||||
}
|
||||
void Digest::Finish(md5_byte_t digest[16])
|
||||
{
|
||||
static const md5_byte_t pad[64] =
|
||||
{
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
md5_byte_t data[8];
|
||||
int i;
|
||||
|
||||
// Save the length before padding.
|
||||
for (i = 0; i < 8; ++i)
|
||||
data[i] = (md5_byte_t)(count[i >> 2] >> ((i & 3) << 3));
|
||||
// Pad to 56 bytes mod 64.
|
||||
Append(pad, ((55 - (count[0] >> 3)) & 63) + 1);
|
||||
// Append the length.
|
||||
Append(data, 8);
|
||||
|
||||
for (i = 0; i < 16; ++i)
|
||||
digest[i] = (md5_byte_t)(abcd[i >> 2] >> ((i & 3) << 3));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GS::MD5::DigestToString(const md5_byte_t digest[16], char *s)
|
||||
{
|
||||
const char hex_table[17] = "0123456789abcdef";
|
||||
|
||||
for (int n = 0; n < 16; ++n)
|
||||
{
|
||||
*s++ = hex_table[(digest[n] >> 4) & 15];
|
||||
*s++ = hex_table[digest[n] & 15];
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
47
include/platform/hash/nsha1.cpp
Normal file
47
include/platform/hash/nsha1.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "hash/nsha1.h"
|
||||
#include "hash/sha1.h"
|
||||
#include "container/narray.h"
|
||||
#include "nstring/nstring.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void SHA1::ComputeHash(const String &source, Array <unsigned char> &hash)
|
||||
{
|
||||
if (hash.Allocate(20))
|
||||
sha1::calc(source.c_str(), source.Len(), hash.c_ptr());
|
||||
}
|
||||
String SHA1::ComputeHexa(const String &source)
|
||||
{
|
||||
Array <unsigned char> hash;
|
||||
ComputeHash(source, hash);
|
||||
|
||||
char hex[41];
|
||||
sha1::toHexString(hash.c_ptr(), hex);
|
||||
return String(hex);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void SHA1::ComputeHash(const Array <char> &data, Array <unsigned char> &hash)
|
||||
{
|
||||
if (hash.Allocate(20))
|
||||
sha1::calc(data.c_ptr(), data.GetSize(), hash.c_ptr());
|
||||
}
|
||||
String SHA1::ComputeHexa(const Array <char> &data)
|
||||
{
|
||||
Array <unsigned char> hash;
|
||||
ComputeHash(data, hash);
|
||||
|
||||
char hex[41];
|
||||
sha1::toHexString(hash.c_ptr(), hex);
|
||||
return String(hex);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
185
include/platform/hash/sha1.cpp
Normal file
185
include/platform/hash/sha1.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
Copyright (c) 2011, Micael Hildenborg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Micael Hildenborg nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
Contributors:
|
||||
Gustav
|
||||
Several members in the gamedev.se forum.
|
||||
Gregory Petrosyan
|
||||
*/
|
||||
|
||||
#include "hash/sha1.h"
|
||||
|
||||
namespace sha1
|
||||
{
|
||||
namespace // local
|
||||
{
|
||||
// Rotate an integer value to left.
|
||||
inline const unsigned int rol(const unsigned int value,
|
||||
const unsigned int steps)
|
||||
{
|
||||
return ((value << steps) | (value >> (32 - steps)));
|
||||
}
|
||||
|
||||
// Sets the first 16 integers in the buffert to zero.
|
||||
// Used for clearing the W buffert.
|
||||
inline void clearWBuffert(unsigned int* buffert)
|
||||
{
|
||||
for (int pos = 16; --pos >= 0;)
|
||||
{
|
||||
buffert[pos] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void innerHash(unsigned int* result, unsigned int* w)
|
||||
{
|
||||
unsigned int a = result[0];
|
||||
unsigned int b = result[1];
|
||||
unsigned int c = result[2];
|
||||
unsigned int d = result[3];
|
||||
unsigned int e = result[4];
|
||||
|
||||
int round = 0;
|
||||
|
||||
#define sha1macro(func,val) \
|
||||
{ \
|
||||
const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
|
||||
e = d; \
|
||||
d = c; \
|
||||
c = rol(b, 30); \
|
||||
b = a; \
|
||||
a = t; \
|
||||
}
|
||||
|
||||
while (round < 16)
|
||||
{
|
||||
sha1macro((b & c) | (~b & d), 0x5a827999)
|
||||
++round;
|
||||
}
|
||||
while (round < 20)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro((b & c) | (~b & d), 0x5a827999)
|
||||
++round;
|
||||
}
|
||||
while (round < 40)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro(b ^ c ^ d, 0x6ed9eba1)
|
||||
++round;
|
||||
}
|
||||
while (round < 60)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
|
||||
++round;
|
||||
}
|
||||
while (round < 80)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro(b ^ c ^ d, 0xca62c1d6)
|
||||
++round;
|
||||
}
|
||||
|
||||
#undef sha1macro
|
||||
|
||||
result[0] += a;
|
||||
result[1] += b;
|
||||
result[2] += c;
|
||||
result[3] += d;
|
||||
result[4] += e;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void calc(const void* src, const int bytelength, unsigned char* hash)
|
||||
{
|
||||
// Init the result array.
|
||||
unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 };
|
||||
|
||||
// Cast the void src pointer to be the byte array we can work with.
|
||||
const unsigned char* sarray = (const unsigned char*) src;
|
||||
|
||||
// The reusable round buffer
|
||||
unsigned int w[80];
|
||||
|
||||
// Loop through all complete 64byte blocks.
|
||||
const int endOfFullBlocks = bytelength - 64;
|
||||
int endCurrentBlock;
|
||||
int currentBlock = 0;
|
||||
|
||||
while (currentBlock <= endOfFullBlocks)
|
||||
{
|
||||
endCurrentBlock = currentBlock + 64;
|
||||
|
||||
// Init the round buffer with the 64 byte block data.
|
||||
for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)
|
||||
{
|
||||
// This line will swap endian on big endian and keep endian on little endian.
|
||||
w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
|
||||
| (((unsigned int) sarray[currentBlock + 2]) << 8)
|
||||
| (((unsigned int) sarray[currentBlock + 1]) << 16)
|
||||
| (((unsigned int) sarray[currentBlock]) << 24);
|
||||
}
|
||||
innerHash(result, w);
|
||||
}
|
||||
|
||||
// Handle the last and not full 64 byte block if existing.
|
||||
endCurrentBlock = bytelength - currentBlock;
|
||||
clearWBuffert(w);
|
||||
int lastBlockBytes = 0;
|
||||
for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes)
|
||||
{
|
||||
w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
|
||||
}
|
||||
w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
|
||||
if (endCurrentBlock >= 56)
|
||||
{
|
||||
innerHash(result, w);
|
||||
clearWBuffert(w);
|
||||
}
|
||||
w[15] = bytelength << 3;
|
||||
innerHash(result, w);
|
||||
|
||||
// Store hash in result pointer, and make sure we get in in the correct order on both endian models.
|
||||
for (int hashByte = 20; --hashByte >= 0;)
|
||||
{
|
||||
hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
void toHexString(const unsigned char* hash, char* hexstring)
|
||||
{
|
||||
const char hexDigits[] = { "0123456789abcdef" };
|
||||
|
||||
for (int hashByte = 20; --hashByte >= 0;)
|
||||
{
|
||||
hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf];
|
||||
hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf];
|
||||
}
|
||||
hexstring[40] = 0;
|
||||
}
|
||||
} // namespace sha1
|
||||
19
include/platform/input/input_keyboard.cpp
Normal file
19
include/platform/input/input_keyboard.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "input/input_keyboard.h"
|
||||
#include "memory/memory.h"
|
||||
|
||||
using namespace GS::Input;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Keyboard::Keyboard()
|
||||
{
|
||||
GS::Memory::Set(is_down, 0, sizeof(bool) * (uint)Key_Last);
|
||||
GS::Memory::Set(was_down, 0, sizeof(bool) * (uint)Key_Last);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
102
include/platform/input/input_mouse.cpp
Normal file
102
include/platform/input/input_mouse.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "input/input_mouse.h"
|
||||
|
||||
using namespace GS::Input;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Mouse::IsDown(KeyCode key) const
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case Key_Button0: return state.left_button;
|
||||
case Key_Button1: return state.right_button;
|
||||
case Key_Button2: return state.middle_button;
|
||||
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool Mouse::WasDown(KeyCode key) const
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case Key_Button0: return last_state.left_button;
|
||||
case Key_Button1: return last_state.right_button;
|
||||
case Key_Button2: return last_state.middle_button;
|
||||
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Mouse::GetInputRange(InputCode i, float &mn, float &mx) const
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case Input_AxisX:
|
||||
case Input_AxisY:
|
||||
mn = 0; mx = 1;
|
||||
return true;
|
||||
|
||||
case Input_RotX: // Horizontal wheel.
|
||||
case Input_RotY: // Vertical wheel.
|
||||
mn = 0; mx = 1024;
|
||||
return true;
|
||||
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
float Mouse::GetValue(InputCode i) const
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case Input_AxisX: return state.x;
|
||||
case Input_AxisY: return state.y;
|
||||
case Input_RotX: return state.hwheel;
|
||||
case Input_RotY: return state.wheel;
|
||||
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
float Mouse::GetLastValue(InputCode i) const
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case Input_AxisX: return last_state.x;
|
||||
case Input_AxisY: return last_state.y;
|
||||
case Input_RotX: return last_state.hwheel;
|
||||
case Input_RotY: return last_state.wheel;
|
||||
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Mouse::Mouse()
|
||||
{
|
||||
state.x = 0; state.y = 0;
|
||||
|
||||
state.left_button = false;
|
||||
state.right_button = false;
|
||||
state.middle_button = false;
|
||||
state.wheel = 0;
|
||||
state.hwheel = 0;
|
||||
|
||||
last_state = state;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
96
include/platform/input/input_touch.cpp
Normal file
96
include/platform/input/input_touch.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "input/input_touch.h"
|
||||
#include "nstring/nstring.h"
|
||||
|
||||
using namespace GS::Input;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void TouchDevice::RegisterTouchEvent(float x, float y, float weight)
|
||||
{
|
||||
pending_state.button = asbool(weight > 0);
|
||||
pending_state.x = x;
|
||||
pending_state.y = y;
|
||||
}
|
||||
void TouchDevice::Update()
|
||||
{
|
||||
last_state = state;
|
||||
state = pending_state;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool TouchDevice::IsDown(KeyCode key) const
|
||||
{ return key == Key_Button0 ? state.button : false; }
|
||||
bool TouchDevice::WasDown(KeyCode key) const
|
||||
{ return key == Key_Button0 ? last_state.button : false; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool TouchDevice::GetInputRange(InputCode i, float &mn, float &mx) const
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case Input_AxisX:
|
||||
case Input_AxisY:
|
||||
mn = 0; mx = 1;
|
||||
return true;
|
||||
|
||||
case Input_RotX: // Horizontal wheel.
|
||||
case Input_RotY: // Vertical wheel.
|
||||
mn = 0; mx = 1024;
|
||||
return true;
|
||||
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
float TouchDevice::GetValue(InputCode i) const
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case Input_AxisX: return state.x;
|
||||
case Input_AxisY: return state.y;
|
||||
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
float TouchDevice::GetLastValue(InputCode i) const
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case Input_AxisX: return last_state.x;
|
||||
case Input_AxisY: return last_state.y;
|
||||
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void TouchDevice::SetIndex(int _index)
|
||||
{ index = _index; }
|
||||
Device::Type TouchDevice::GetType() const
|
||||
{ return index == -1 ? Type_Mouse : Type_Touch; }
|
||||
const char *TouchDevice::GetName() const
|
||||
{ return index == -1 ? "mouse" : GS::String::Format("touch%d", index).c_str(); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
TouchDevice::TouchDevice(int i) : index(i)
|
||||
{
|
||||
state.x = 0; state.y = 0;
|
||||
state.button = false;
|
||||
pending_state = last_state = state;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
285
include/platform/locale/country.cpp
Normal file
285
include/platform/locale/country.cpp
Normal file
@ -0,0 +1,285 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "locale/country.h"
|
||||
|
||||
|
||||
namespace GS {
|
||||
namespace Locale {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static Info countries[] =
|
||||
{
|
||||
{ "Asia", "South Asia", "Afghanistan", "AF", "AF", "AFG", 4, "AF" },
|
||||
{ "Europe", "South East Europe", "Albania", "AL", "AL", "ALB", 8, "AL" },
|
||||
{ "Africa", "Northern Africa", "Algeria", "AG", "DZ", "DZA", 12, "DZ" },
|
||||
{ "Oceania", "Pacific", "American Samoa", "AQ", "AS", "ASM", 16, "AS" },
|
||||
{ "Europe", "South West Europe", "Andorra", "AN", "AD", "AND", 20, "AD" },
|
||||
{ "Africa", "Southern Africa", "Angola", "AO", "AO", "AGO", 24, "AO" },
|
||||
{ "Americas", "West Indies", "Anguilla", "AV", "AI", "AIA", 660, "AI" },
|
||||
{ "Americas", "West Indies", "Antigua and Barbuda", "AC", "AG", "ATG", 28, "AG" },
|
||||
{ "Americas", "South America", "Argentina", "AR", "AR", "ARG", 32, "AR" },
|
||||
{ "Asia", "South West Asia", "Armenia", "AM", "AM", "ARM", 51, "AM" },
|
||||
{ "Americas", "West Indies", "Aruba", "AA", "AW", "ABW", 533, "AW" },
|
||||
{ "Oceania", "Pacific", "Australia", "AS", "AU", "AUS", 36, "AU" },
|
||||
{ "Europe", "Central Europe", "Austria", "AU", "AT", "AUT", 40, "AT" },
|
||||
{ "Asia", "South West Asia", "Azerbaijan", "AJ", "AZ", "AZE", 31, "AZ" },
|
||||
{ "Americas", "West Indies", "Bahamas, The", "BF", "BS", "BHS", 44, "BS" },
|
||||
{ "Asia", "South West Asia", "Bahrain", "BA", "BH", "BHR", 48, "BH" },
|
||||
{ "Asia", "South Asia", "Bangladesh", "BG", "BD", "BGD", 50, "BD" },
|
||||
{ "Americas", "West Indies", "Barbados", "BB", "BB", "BRB", 52, "BB" },
|
||||
{ "Europe", "Eastern Europe", "Belarus", "BO", "BY", "BLR", 112, "BY" },
|
||||
{ "Europe", "Western Europe", "Belgium", "BE", "BE", "BEL", 56, "BE" },
|
||||
{ "Americas", "Central America", "Belize", "BH", "BZ", "BLZ", 84, "BZ" },
|
||||
{ "Africa", "Western Africa", "Benin", "BN", "BJ", "BEN", 204, "BJ" },
|
||||
{ "Americas", "West Indies", "Bermuda", "BD", "BM", "BMU", 60, "BM" },
|
||||
{ "Asia", "South Asia", "Bhutan", "BT", "BT", "BTN", 64, "BT" },
|
||||
{ "Americas", "South America", "Bolivia", "BL", "BO", "BOL", 68, "BO" },
|
||||
{ "Europe", "South East Europe", "Bosnia and Herzegovina", "BK", "BA", "BIH", 70, "BA" },
|
||||
{ "Africa", "Southern Africa", "Botswana", "BC", "BW", "BWA", 72, "BW" },
|
||||
{ "Americas", "South America", "Brazil", "BR", "BR", "BRA", 76, "BR" },
|
||||
{ "Americas", "West Indies", "British Virgin Islands", "VI", "VG", "VGB", 92, "VG" },
|
||||
{ "Asia", "South East Asia", "Brunei", "BX", "BN", "BRN", 96, "BN" },
|
||||
{ "Europe", "South East Europe", "Bulgaria", "BU", "BG", "BGR", 100, "BG" },
|
||||
{ "Africa", "Western Africa", "Burkina Faso", "UV", "BF", "BFA", 854, "BF" },
|
||||
{ "Africa", "Central Africa", "Burundi", "BY", "BI", "BDI", 108, "BI" },
|
||||
{ "Asia", "South East Asia", "Cambodia", "CB", "KH", "KHM", 116, "KH" },
|
||||
{ "Africa", "Western Africa", "Cameroon", "CM", "CM", "CMR", 120, "CM" },
|
||||
{ "Americas", "North America", "Canada", "CA", "CA", "CAN", 124, "CA" },
|
||||
{ "Africa", "Western Africa", "Cape Verde", "CV", "CV", "CPV", 132, "CV" },
|
||||
{ "Americas", "West Indies", "Cayman Islands", "CJ", "KY", "CYM", 136, "KY" },
|
||||
{ "Africa", "Central Africa", "Central African Republic", "CT", "CF", "CAF", 140, "CF" },
|
||||
{ "Africa", "Central Africa", "Chad", "CD", "TD", "TCD", 148, "TD" },
|
||||
{ "Americas", "South America", "Chile", "CI", "CL", "CHL", 152, "CL" },
|
||||
{ "Asia", "East Asia", "China", "CH", "CN", "CHN", 156, "CN" },
|
||||
{ "Asia", "South East Asia", "Christmas Island", "KT", "CX", "CXR", 162, "CX" },
|
||||
{ "Asia", "South East Asia", "Cocos (Keeling) Islands", "CK", "CC", "CCK", 166, "CC" },
|
||||
{ "Americas", "South America", "Colombia", "CO", "CO", "COL", 170, "CO" },
|
||||
{ "Africa", "Indian Ocean", "Comoros", "CN", "KM", "COM", 174, "KM" },
|
||||
{ "Africa", "Central Africa", "Congo, Republic of the", "CF", "CG", "COG", 178, "CG" },
|
||||
{ "Oceania", "Pacific", "Cook Islands", "CW", "CK", "COK", 184, "CK" },
|
||||
{ "Americas", "Central America", "Costa Rica", "CS", "CR", "CRI", 188, "CR" },
|
||||
{ "Africa", "Western Africa", "Cote d'Ivoire", "IV", "CI", "CIV", 384, "CI" },
|
||||
{ "Europe", "South East Europe", "Croatia", "HR", "HR", "HRV", 191, "HR" },
|
||||
{ "Americas", "West Indies", "Cuba", "CU", "CU", "CUB", 192, "CU" },
|
||||
{ "Asia", "South West Asia", "Cyprus", "CY", "CY", "CYP", 196, "CY" },
|
||||
{ "Europe", "Central Europe", "Czech Republic", "EZ", "CZ", "CZE", 203, "CZ" },
|
||||
{ "Europe", "Northern Europe", "Denmark", "DA", "DK", "DNK", 208, "DK" },
|
||||
{ "Africa", "Eastern Africa", "Djibouti", "DJ", "DJ", "DJI", 262, "DJ" },
|
||||
{ "Americas", "West Indies", "Dominica", "DO", "DM", "DMA", 212, "DM" },
|
||||
{ "Americas", "West Indies", "Dominican Republic", "DR", "DO", "DOM", 214, "DO" },
|
||||
{ "Americas", "South America", "Ecuador", "EC", "EC", "ECU", 218, "EC" },
|
||||
{ "Africa", "Northern Africa", "Egypt", "EG", "EG", "EGY", 818, "EG" },
|
||||
{ "Americas", "Central America", "El Salvador", "ES", "SV", "SLV", 222, "SV" },
|
||||
{ "Africa", "Western Africa", "Equatorial Guinea", "EK", "GQ", "GNQ", 226, "GQ" },
|
||||
{ "Africa", "Eastern Africa", "Eritrea", "ER", "ER", "ERI", 232, "ER" },
|
||||
{ "Europe", "Eastern Europe", "Estonia", "EN", "EE", "EST", 233, "EE" },
|
||||
{ "Africa", "Eastern Africa", "Ethiopia", "ET", "ET", "ETH", 231, "ET" },
|
||||
{ "Americas", "South America", "Falkland Islands (Islas Malvinas)", "FA", "FK", "FLK", 238, "FK" },
|
||||
{ "Europe", "Northern Europe", "Faroe Islands", "FO", "FO", "FRO", 234, "FO" },
|
||||
{ "Oceania", "Pacific", "Fiji", "FJ", "FJ", "FJI", 242, "FJ" },
|
||||
{ "Europe", "Northern Europe", "Finland", "FI", "FI", "FIN", 246, "FI" },
|
||||
{ "Europe", "Western Europe", "France", "FR", "FR", "FRA", 250, "FR" },
|
||||
{ "Americas", "South America", "French Guiana", "FG", "GF", "GUF", 254, "GF" },
|
||||
{ "Oceania", "Pacific", "French Polynesia", "FP", "PF", "PYF", 258, "PF" },
|
||||
{ "Africa", "Western Africa", "Gabon", "GB", "GA", "GAB", 266, "GA" },
|
||||
{ "Africa", "Western Africa", "Gambia, The", "GA", "GM", "GMB", 270, "GM" },
|
||||
{ "Asia", "South West Asia", "Georgia", "GG", "GE", "GEO", 268, "GE" },
|
||||
{ "Europe", "Western Europe", "Germany", "GM", "DE", "DEU", 276, "DE" },
|
||||
{ "Africa", "Western Africa", "Ghana", "GH", "GH", "GHA", 288, "GH" },
|
||||
{ "Europe", "South West Europe", "Gibraltar", "GI", "GI", "GIB", 292, "GI" },
|
||||
{ "Europe", "South East Europe", "Greece", "GR", "GR", "GRC", 300, "GR" },
|
||||
{ "Americas", "North America", "Greenland", "GL", "GL", "GRL", 304, "GL" },
|
||||
{ "Americas", "West Indies", "Grenada", "GJ", "GD", "GRD", 308, "GD" },
|
||||
{ "Americas", "West Indies", "Guadeloupe", "GP", "GP", "GLP", 312, "GP" },
|
||||
{ "Oceania", "Pacific", "Guam", "GQ", "GU", "GUM", 316, "GU" },
|
||||
{ "Americas", "Central America", "Guatemala", "GT", "GT", "GTM", 320, "GT" },
|
||||
{ "Europe", "Western Europe", "Guernsey", "--", "--", "--", 0, "--" },
|
||||
{ "Africa", "Western Africa", "Guinea", "GV", "GN", "GIN", 324, "GN" },
|
||||
{ "Africa", "Western Africa", "Guinea-Bissau", "PU", "GW", "GNB", 624, "GW" },
|
||||
{ "Americas", "South America", "Guyana", "GY", "GY", "GUY", 328, "GY" },
|
||||
{ "Americas", "West Indies", "Haiti", "HA", "HT", "HTI", 332, "HT" },
|
||||
{ "Europe", "Southern Europe", "Holy See (Vatican City)", "VT", "VA", "VAT", 336, "VA" },
|
||||
{ "Americas", "Central America", "Honduras", "HO", "HN", "HND", 340, "HN" },
|
||||
{ "Europe", "Central Europe", "Hungary", "HU", "HU", "HUN", 348, "HU" },
|
||||
{ "Europe", "Northern Europe", "Iceland", "IC", "IS", "ISL", 352, "IS" },
|
||||
{ "Asia", "South Asia", "India", "IN", "IN", "IND", 356, "IN" },
|
||||
{ "Asia", "South East Asia", "Indonesia", "ID", "ID", "IDN", 360, "ID" },
|
||||
{ "Asia", "South West Asia", "Iran", "IR", "IR", "IRN", 364, "IR" },
|
||||
{ "Asia", "South West Asia", "Iraq", "IZ", "IQ", "IRQ", 368, "IQ" },
|
||||
{ "Europe", "Western Europe", "Ireland", "EI", "IE", "IRL", 372, "IE" },
|
||||
{ "Asia", "South West Asia", "Israel", "IS", "IL", "ISR", 376, "IL" },
|
||||
{ "Europe", "Southern Europe", "Italy", "IT", "IT", "ITA", 380, "IT" },
|
||||
{ "Americas", "West Indies", "Jamaica", "JM", "JM", "JAM", 388, "JM" },
|
||||
{ "Europe", "Northern Europe", "Jan Mayen", "--", "--", "--", 0, "--" },
|
||||
{ "Asia", "East Asia", "Japan", "JA", "JP", "JPN", 392, "JP" },
|
||||
{ "Europe", "Western Europe", "Jersey", "--", "--", "--", 0, "--" },
|
||||
{ "Asia", "South West Asia", "Jordan", "JO", "JO", "JOR", 400, "JO" },
|
||||
{ "Asia", "Central Asia", "Kazakhstan", "KZ", "KZ", "KAZ", 398, "KZ" },
|
||||
{ "Africa", "Eastern Africa", "Kenya", "KE", "KE", "KEN", 404, "KE" },
|
||||
{ "Oceania", "Pacific", "Kiribati", "KR", "KI", "KIR", 296, "KI" },
|
||||
{ "Asia", "East Asia", "Korea, North", "KN", "KP", "PRK", 408, "KP" },
|
||||
{ "Asia", "East Asia", "Korea, South", "KS", "KR", "KOR", 410, "KR" },
|
||||
{ "Asia", "South West Asia", "Kuwait", "KU", "KW", "KWT", 414, "KW" },
|
||||
{ "Asia", "Central Asia", "Kyrgyzstan", "KG", "KG", "KGZ", 417, "KG" },
|
||||
{ "Asia", "South East Asia", "Laos", "LA", "LA", "LAO", 418, "LA" },
|
||||
{ "Europe", "Eastern Europe", "Latvia", "LG", "LV", "LVA", 428, "LV" },
|
||||
{ "Asia", "South West Asia", "Lebanon", "LE", "LB", "LBN", 422, "LB" },
|
||||
{ "Africa", "Southern Africa", "Lesotho", "LT", "LS", "LSO", 426, "LS" },
|
||||
{ "Africa", "Western Africa", "Liberia", "LI", "LR", "LBR", 430, "LR" },
|
||||
{ "Africa", "Northern Africa", "Libya", "LY", "LY", "LBY", 434, "LY" },
|
||||
{ "Europe", "Central Europe", "Liechtenstein", "LS", "LI", "LIE", 438, "LI" },
|
||||
{ "Europe", "Eastern Europe", "Lithuania", "LH", "LT", "LTU", 440, "LT" },
|
||||
{ "Europe", "Western Europe", "Luxembourg", "LU", "LU", "LUX", 442, "LU" },
|
||||
{ "Europe", "South East Europe", "Macedonia", "MK", "MK", "MKD", 807, "MK" },
|
||||
{ "Africa", "Indian Ocean", "Madagascar", "MA", "MG", "MDG", 450, "MG" },
|
||||
{ "Africa", "Southern Africa", "Malawi", "MI", "MW", "MWI", 454, "MW" },
|
||||
{ "Asia", "South East Asia", "Malaysia", "MY", "MY", "MYS", 458, "MY" },
|
||||
{ "Asia", "South Asia", "Maldives", "MV", "MV", "MDV", 462, "MV" },
|
||||
{ "Africa", "Western Africa", "Mali", "ML", "ML", "MLI", 466, "ML" },
|
||||
{ "Europe", "Southern Europe", "Malta", "MT", "MT", "MLT", 470, "MT" },
|
||||
{ "Europe", "Western Europe", "Man, Isle of", "--", "--", "--", 0, "--" },
|
||||
{ "Oceania", "Pacific", "Marshall Islands", "RM", "MH", "MHL", 584, "MH" },
|
||||
{ "Americas", "West Indies", "Martinique", "MB", "MQ", "MTQ", 474, "MQ" },
|
||||
{ "Africa", "Western Africa", "Mauritania", "MR", "MR", "MRT", 478, "MR" },
|
||||
{ "Africa", "Indian Ocean", "Mauritius", "MP", "MU", "MUS", 480, "MU" },
|
||||
{ "Africa", "Indian Ocean", "Mayotte", "MF", "YT", "MYT", 175, "YT" },
|
||||
{ "Americas", "Central America", "Mexico", "MX", "MX", "MEX", 484, "MX" },
|
||||
{ "Oceania", "Pacific", "Micronesia, Federated States of", "FM", "FSM", "583", 0, "--" },
|
||||
{ "Europe", "Eastern Europe", "Moldova", "MD", "MD", "MDA", 498, "MD" },
|
||||
{ "Europe", "Western Europe", "Monaco", "MN", "MC", "MCO", 492, "MC" },
|
||||
{ "Asia", "Northern Asia", "Mongolia", "MG", "MN", "MNG", 496, "MN" },
|
||||
{ "Americas", "West Indies", "Montserrat", "MH", "MS", "MSR", 500, "MS" },
|
||||
{ "Africa", "Northern Africa", "Morocco", "MO", "MA", "MAR", 504, "MA" },
|
||||
{ "Africa", "Southern Africa", "Mozambique", "MZ", "MZ", "MOZ", 508, "MZ" },
|
||||
{ "Asia", "South East Asia", "Myanmar (Burma)", "BM", "MM", "MMR", 104, "MM" },
|
||||
{ "Africa", "Southern Africa", "Namibia", "WA", "NA", "NAM", 516, "NA" },
|
||||
{ "Oceania", "Pacific", "Nauru", "NR", "NR", "NRU", 520, "NR" },
|
||||
{ "Asia", "South Asia", "Nepal", "NP", "NP", "NPL", 524, "NP" },
|
||||
{ "Europe", "Western Europe", "Netherlands", "NL", "NL", "NLD", 528, "NL" },
|
||||
{ "Americas", "West Indies", "Netherlands Antilles", "NT", "AN", "ANT", 530, "AN" },
|
||||
{ "Oceania", "Pacific", "New Caledonia", "NC", "NC", "NCL", 540, "NC" },
|
||||
{ "Oceania", "Pacific", "New Zealand", "NZ", "NZ", "NZL", 554, "NZ" },
|
||||
{ "Americas", "Central America", "Nicaragua", "NU", "NI", "NIC", 558, "NI" },
|
||||
{ "Africa", "Western Africa", "Niger", "NG", "NE", "NER", 562, "NE" },
|
||||
{ "Africa", "Western Africa", "Nigeria", "NI", "NG", "NGA", 566, "NG" },
|
||||
{ "Oceania", "Pacific", "Niue", "NE", "NU", "NIU", 570, "NU" },
|
||||
{ "Oceania", "Pacific", "Norfolk Island", "NF", "NF", "NFK", 574, "NF" },
|
||||
{ "Oceania", "Pacific", "Northern Mariana Islands", "CQ", "MP", "MNP", 580, "MP" },
|
||||
{ "Europe", "Northern Europe", "Norway", "NO", "NO", "NOR", 578, "NO" },
|
||||
{ "Asia", "South West Asia", "Oman", "MU", "OM", "OMN", 512, "OM" },
|
||||
{ "Asia", "South Asia", "Pakistan", "PK", "PK", "PAK", 586, "PK" },
|
||||
{ "Oceania", "Pacific", "Palau", "PS", "PW", "PLW", 585, "PW" },
|
||||
{ "Asia", "South West Asia", "Palestine", "--", "--", "--", 0, "--" },
|
||||
{ "Americas", "Central America", "Panama", "PM", "PA", "PAN", 591, "PA" },
|
||||
{ "Oceania", "Pacific", "Papua New Guinea", "PP", "PG", "PNG", 598, "PG" },
|
||||
{ "Americas", "South America", "Paraguay", "PA", "PY", "PRY", 600, "PY" },
|
||||
{ "Americas", "South America", "Peru", "PE", "PE", "PER", 604, "PE" },
|
||||
{ "Asia", "South East Asia", "Philippines", "RP", "PH", "PHL", 608, "PH" },
|
||||
{ "Oceania", "Pacific", "Pitcairn Islands", "PC", "PN", "PCN", 612, "PN" },
|
||||
{ "Europe", "Eastern Europe", "Poland", "PL", "PL", "POL", 616, "PL" },
|
||||
{ "Europe", "South West Europe", "Portugal", "PO", "PT", "PRT", 620, "PT" },
|
||||
{ "Americas", "West Indies", "Puerto Rico", "RQ", "PR", "PRI", 630, "PR" },
|
||||
{ "Asia", "South West Asia", "Qatar", "QA", "QA", "QAT", 634, "QA" },
|
||||
{ "Africa", "Indian Ocean", "Reunion", "RE", "RE", "REU", 638, "RE" },
|
||||
{ "Europe", "South East Europe", "Romania", "RO", "RO", "ROM", 642, "RO" },
|
||||
{ "Asia", "Northern Asia", "Russia", "RS", "RU", "RUS", 643, "RU" },
|
||||
{ "Africa", "Central Africa", "Rwanda", "RW", "RW", "RWA", 646, "RW" },
|
||||
{ "Americas", "West Indies", "Saint Kitts and Nevis", "SC", "KN", "KNA", 659, "KN" },
|
||||
{ "Americas", "West Indies", "Saint Lucia", "ST", "LC", "LCA", 662, "LC" },
|
||||
{ "Americas", "North America", "Saint Pierre and Miquelon", "SB", "PM", "SPM", 666, "PM" },
|
||||
{ "Americas", "West Indies", "Saint Vincent and the Grenadines", "VC", "VC", "VCT", 670, "VC" },
|
||||
{ "Europe", "Southern Europe", "San Marino", "SM", "SM", "SMR", 674, "SM" },
|
||||
{ "Africa", "Western Africa", "Sao Tome and Principe", "TP", "ST", "STP", 678, "ST" },
|
||||
{ "Asia", "South West Asia", "Saudi Arabia", "SA", "SA", "SAU", 682, "SA" },
|
||||
{ "Africa", "Western Africa", "Senegal", "SG", "SN", "SEN", 686, "SN" },
|
||||
{ "Europe", "South East Europe", "Serbia and Montenegro", "SR", "--", "--", 0, "--" },
|
||||
{ "Africa", "Indian Ocean", "Seychelles", "SE", "SC", "SYC", 690, "SC" },
|
||||
{ "Africa", "Western Africa", "Sierra Leone", "SL", "SL", "SLE", 694, "SL" },
|
||||
{ "Asia", "South East Asia", "Singapore", "SN", "SG", "SGP", 702, "SG" },
|
||||
{ "Europe", "Central Europe", "Slovakia", "LO", "SK", "SVK", 703, "SK" },
|
||||
{ "Europe", "South East Europe", "Slovenia", "SI", "SI", "SVN", 705, "SI" },
|
||||
{ "Oceania", "Pacific", "Solomon Islands", "BP", "SB", "SLB", 90, "SB" },
|
||||
{ "Africa", "Eastern Africa", "Somalia", "SO", "SO", "SOM", 706, "SO" },
|
||||
{ "Africa", "Southern Africa", "South Africa", "SF", "ZA", "ZAF", 710, "ZA" },
|
||||
{ "Europe", "South West Europe", "Spain", "SP", "ES", "ESP", 724, "ES" },
|
||||
{ "Asia", "South Asia", "Sri Lanka", "CE", "LK", "LKA", 144, "LK" },
|
||||
{ "Africa", "Northern Africa", "Sudan", "SU", "SD", "SDN", 736, "SD" },
|
||||
{ "Americas", "South America", "Suriname", "NS", "SR", "SUR", 740, "SR" },
|
||||
{ "Europe", "Northern Europe", "Svalbard", "SV", "SJ", "SJM", 744, "SJ" },
|
||||
{ "Africa", "Southern Africa", "Swaziland", "WZ", "SZ", "SWZ", 748, "SZ" },
|
||||
{ "Europe", "Northern Europe", "Sweden", "SW", "SE", "SWE", 752, "SE" },
|
||||
{ "Europe", "Central Europe", "Switzerland", "SZ", "CH", "CHE", 756, "CH" },
|
||||
{ "Asia", "South West Asia", "Syria", "SY", "SY", "SYR", 760, "SY" },
|
||||
{ "Asia", "East Asia", "Taiwan", "TW", "TW", "TWN", 158, "TW" },
|
||||
{ "Asia", "Central Asia", "Tajikistan", "TI", "TJ", "TJK", 762, "TJ" },
|
||||
{ "Africa", "Eastern Africa", "Tanzania", "TZ", "TZ", "TZA", 834, "TZ" },
|
||||
{ "Asia", "South East Asia", "Thailand", "TH", "TH", "THA", 764, "TH" },
|
||||
{ "Africa", "Western Africa", "Togo", "TO", "TG", "TGO", 768, "TG" },
|
||||
{ "Oceania", "Pacific", "Tokelau", "TL", "TK", "TKL", 772, "TK" },
|
||||
{ "Oceania", "Pacific", "Tonga", "TN", "TO", "TON", 776, "TO" },
|
||||
{ "Americas", "West Indies", "Trinidad and Tobago", "TD", "TT", "TTO", 780, "TT" },
|
||||
{ "Africa", "Northern Africa", "Tunisia", "TS", "TN", "TUN", 788, "TN" },
|
||||
{ "Asia", "South West Asia", "Turkey", "TU", "TR", "TUR", 792, "TR" },
|
||||
{ "Asia", "Central Asia", "Turkmenistan", "TX", "TM", "TKM", 795, "TM" },
|
||||
{ "Americas", "West Indies", "Turks and Caicos Islands", "TK", "TC", "TCA", 796, "TC" },
|
||||
{ "Oceania", "Pacific", "Tuvalu", "TV", "TV", "TUV", 798, "TV" },
|
||||
{ "Africa", "Eastern Africa", "Uganda", "UG", "UG", "UGA", 800, "UG" },
|
||||
{ "Europe", "Eastern Europe", "Ukraine", "UP", "UA", "UKR", 804, "UA" },
|
||||
{ "Asia", "South West Asia", "United Arab Emirates", "TC", "AE", "ARE", 784, "AE" },
|
||||
{ "Europe", "Western Europe", "United Kingdom", "UK", "GB", "GBR", 826, "UK/GB" },
|
||||
{ "Americas", "North America", "United States", "US", "US", "USA", 840, "US" },
|
||||
{ "Americas", "South America", "Uruguay", "UY", "UY", "URY", 858, "UY" },
|
||||
{ "Asia", "Central Asia", "Uzbekistan", "UZ", "UZ", "UZB", 860, "UZ" },
|
||||
{ "Oceania", "Pacific", "Vanuatu", "NH", "VU", "VUT", 548, "VU" },
|
||||
{ "Americas", "South America", "Venezuela", "VE", "VE", "VEN", 862, "UE" },
|
||||
{ "Asia", "South East Asia", "Vietnam", "VM", "VN", "VNM", 704, "VN" },
|
||||
{ "Americas", "West Indies", "Virgin Islands", "VQ", "VI", "VIR", 850, "VI" },
|
||||
{ "Oceania", "Pacific", "Wallis and Futuna", "WF", "WF", "WLF", 876, "WF" },
|
||||
{ "Africa", "Northern Africa", "Western Sahara", "WI", "EH", "ESH", 732, "EH" },
|
||||
{ "Oceania", "Pacific", "Western Samoa", "WS", "WS", "WSM", 882, "WS" },
|
||||
{ "Asia", "South West Asia", "Yemen", "YM", "YE", "YEM", 887, "YE" },
|
||||
{ "Africa", "Central Africa", "Zaire (Dem Rep of Congo)", "CG", "ZR", "ZAR", 180, "ZR" },
|
||||
{ "Africa", "Southern Africa", "Zambia", "ZA", "ZM", "ZWB", 894, "ZM" },
|
||||
{ "Africa", "Southern Africa", "Zimbabwe", "ZI", "ZW", "ZWE", 716, "ZW" },
|
||||
|
||||
{ 0, 0, 0, 0, 0, 0, -1, 0 }
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const Info *GetFIPSCountry(const char *fips)
|
||||
{
|
||||
for (int n = 0; countries[n].iso != -1; ++n)
|
||||
if (countries[n].fips == fips)
|
||||
return &countries[n];
|
||||
return NULL;
|
||||
}
|
||||
const Info *GetISO2Country(const char *iso)
|
||||
{
|
||||
for (int n = 0; countries[n].iso != -1; ++n)
|
||||
if (countries[n].iso2 == iso)
|
||||
return &countries[n];
|
||||
return NULL;
|
||||
}
|
||||
const Info *GetISO3Country(const char *iso)
|
||||
{
|
||||
for (int n = 0; countries[n].iso != -1; ++n)
|
||||
if (countries[n].iso3 == iso)
|
||||
return &countries[n];
|
||||
return NULL;
|
||||
}
|
||||
const Info *GetISOCountry(int iso)
|
||||
{
|
||||
for (int n = 0; countries[n].iso != -1; ++n)
|
||||
if (countries[n].iso == iso)
|
||||
return &countries[n];
|
||||
return NULL;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
} // Locale
|
||||
} // GS
|
||||
39
include/platform/log/file_log.cpp
Normal file
39
include/platform/log/file_log.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "log/file_log.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "platform.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void FileLog::NewLog(const char *log, char entry_level)
|
||||
{
|
||||
if (FILE *f = fopen(path, initial_write ? "w" : "a"))
|
||||
{
|
||||
initial_write = false;
|
||||
|
||||
if (do_timestamp)
|
||||
{
|
||||
String timestamp = Platform::Get().GetTime().toString() + ": ";
|
||||
fwrite(timestamp.c_str(), 1, timestamp.Len(), f);
|
||||
}
|
||||
|
||||
fwrite(log, 1, String::strlen(log), f);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
FileLog::FileLog(const char *_path, bool _do_timestamp) : path(_path), do_timestamp(_do_timestamp)
|
||||
{
|
||||
initial_write = true;
|
||||
FILE *f = fopen(path, "w");
|
||||
if(f)
|
||||
fclose(f);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
160
include/platform/log/log.cpp
Normal file
160
include/platform/log/log.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include "log/log.h"
|
||||
#include "nstring/nstring.h"
|
||||
#include "thread/mutex.h"
|
||||
#include "platform_config.h"
|
||||
#include "alloc/ialloc.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
template<> LogSystem *Singleton <LogSystem> ::i = NULL;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
LogSystem::LogSystem()
|
||||
{ SetLog(); }
|
||||
void LogSystem::SetLog(Log *l)
|
||||
{
|
||||
static Log s_log;
|
||||
log = l ? l : &s_log;
|
||||
}
|
||||
Log &LogSystem::GetLog()
|
||||
{ return *log; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if __PLATFORM_LOG_SUPPORT__
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Log::NewLog(const char *log, char)
|
||||
{
|
||||
// std::cout << log;
|
||||
}
|
||||
void Log::LogProcessed()
|
||||
{
|
||||
full_a[0] = 0;
|
||||
full_b[0] = 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#define _FORMAT_LOG(__F__, __V__) \
|
||||
{\
|
||||
Threading::MutexLock lock(mutex);\
|
||||
if (a)\
|
||||
{\
|
||||
_snprintf(b, LOG_LINE_MAX_LEN - 1, __F__, a, __V__);\
|
||||
char *swp = a; a = b; b = swp;\
|
||||
}\
|
||||
return *this;\
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Log &Log::operator << (const char v)
|
||||
{ _FORMAT_LOG("%s%d", v) }
|
||||
Log &Log::operator << (const short v)
|
||||
{ _FORMAT_LOG("%s%d", v) }
|
||||
Log &Log::operator << (const int v)
|
||||
{ _FORMAT_LOG("%s%d", v) }
|
||||
Log &Log::operator << (const uchar v)
|
||||
{ _FORMAT_LOG("%s%d", v) }
|
||||
Log &Log::operator << (const ushort v)
|
||||
{ _FORMAT_LOG("%s%d", v) }
|
||||
Log &Log::operator << (const uint v)
|
||||
{ _FORMAT_LOG("%s%d", (int)v) }
|
||||
Log &Log::operator << (const size_t v)
|
||||
{ _FORMAT_LOG("%s%d", v) }
|
||||
Log &Log::operator << (const float v)
|
||||
{ _FORMAT_LOG("%s%.3f", v) }
|
||||
Log &Log::operator << (const bool v)
|
||||
{ _FORMAT_LOG("%s%s", v ? "True" : "False") }
|
||||
Log &Log::operator << (const void *v)
|
||||
{ _FORMAT_LOG("%s0x%p", v) }
|
||||
Log &Log::operator << (const char *v)
|
||||
{
|
||||
if (a && v)
|
||||
{
|
||||
Threading::MutexLock lock(mutex);
|
||||
|
||||
_snprintf(b, LOG_LINE_MAX_LEN - 1, "%s%s", a, v);
|
||||
char *swp = a; a = b; b = swp;
|
||||
|
||||
// Look out for ENDL.
|
||||
for (const char *p = v; p[0]; ++p)
|
||||
if (p[0] == '\n')
|
||||
{
|
||||
// Compute entry level.
|
||||
char entry_level = EngineLogStandard;
|
||||
|
||||
if ((std::strlen(a) >= 3) && (a[0] == '[') && (a[2] == ']'))
|
||||
switch (a[1])
|
||||
{
|
||||
case '*': entry_level |= EngineLogWarning; break;
|
||||
case '!': entry_level |= EngineLogError; break;
|
||||
case 'H': entry_level |= EngineLogHeader; break;
|
||||
case 'V': entry_level |= EngineLogVerbose; break;
|
||||
case 'S': entry_level |= EngineLogScript; break;
|
||||
}
|
||||
|
||||
// Process output.
|
||||
if (entry_level & log_level)
|
||||
NewLog(a, entry_level);
|
||||
|
||||
LogProcessed();
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
Log &Log::operator << (const String &v)
|
||||
{ return *this << v.toUtf8(); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Log::Log()
|
||||
{
|
||||
LogProcessed();
|
||||
a = full_a;
|
||||
b = full_b;
|
||||
log_level = (uint)EngineLogAll;
|
||||
|
||||
mutex = new Threading::Mutex;
|
||||
}
|
||||
Log::~Log()
|
||||
{
|
||||
_safe_delete(mutex);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#else
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Log::NewLog(const char *, char) {}
|
||||
void Log::LogProcessed() {}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Log &Log::operator << (const char) { return *this; }
|
||||
Log &Log::operator << (const short) { return *this; }
|
||||
Log &Log::operator << (const int) { return *this; }
|
||||
Log &Log::operator << (const uchar) { return *this; }
|
||||
Log &Log::operator << (const ushort) { return *this; }
|
||||
Log &Log::operator << (const uint) { return *this; }
|
||||
Log &Log::operator << (const size_t) { return *this; }
|
||||
Log &Log::operator << (const float) { return *this; }
|
||||
Log &Log::operator << (const bool) { return *this; }
|
||||
Log &Log::operator << (const char *) { return *this; }
|
||||
Log &Log::operator << (const String &) { return *this; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Log::Log() {}
|
||||
Log::~Log() {}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
@ -34,7 +34,7 @@ namespace GS {
|
||||
* __LOG_H__: Header (eg: __LOG_H__ << "Physics entry point.\n")
|
||||
* __LOG_W__: Warning
|
||||
* __LOG_E__: Error
|
||||
* __LOG_E__: Non-maskable
|
||||
* __LOG_N__: Non-maskable
|
||||
|
||||
Standard logs may be output to the __LOG__ stream.
|
||||
|
||||
@ -81,9 +81,9 @@ public:
|
||||
Log &operator << (const uchar);
|
||||
Log &operator << (const ushort);
|
||||
Log &operator << (const uint);
|
||||
#if __PLATFORM_IOS__
|
||||
|
||||
Log &operator << (const size_t);
|
||||
#endif
|
||||
|
||||
Log &operator << (const float);
|
||||
Log &operator << (const bool);
|
||||
Log &operator << (const void *);
|
||||
@ -117,7 +117,6 @@ public:
|
||||
//------------------------------------------------------------------------------
|
||||
#define __LOG__ GS::LogSystem::Get().GetLog() // Standard
|
||||
#define __LOG_H__ __LOG__ << "[H] " // Header
|
||||
#define __LOG_CAM__ __LOG__ << "[WEBCAM] " // Header
|
||||
#if 0
|
||||
#define __LOG_W__ __LOG__ << "[*] " << __FUNCTION__ << " (" << __FILE__ << ":" << __LINE__ << ") " // Warning
|
||||
#define __LOG_E__ __LOG__ << "[!] " << __FUNCTION__ << " (" << __FILE__ << ":" << __LINE__ << ") " // Error
|
||||
@ -126,6 +125,8 @@ public:
|
||||
#define __LOG_E__ __LOG__ << "[!] "
|
||||
#endif
|
||||
#define __LOG_V__ __LOG__ << "[V] " // Verbose
|
||||
#define __LOG_SENS__ __LOG__ << "[REALSENSE] " // Verbose
|
||||
#define __LOG_CAM__ __LOG__ << "[WEBCAM] " // Verbose
|
||||
#define __LOG_F__ __LOG__ << __FUNCTION__ << ": "
|
||||
|
||||
#define __LOG_FUNC__ __LOG_V__ << __FUNCTION__ << "\n";
|
||||
|
||||
18
include/platform/log/log_scope.cpp
Normal file
18
include/platform/log/log_scope.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "log/log_scope.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
LogScope::LogScope(const char *s, const char *e) : exit(e)
|
||||
{ __LOG_H__ << s; }
|
||||
LogScope::~LogScope()
|
||||
{ __LOG_H__ << exit; }
|
||||
//------------------------------------------------------------------------------
|
||||
127
include/platform/math/nmath.cpp
Normal file
127
include/platform/math/nmath.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
#include "math/nmath.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Math::rOrder Math::ReverserRotationOrder(rOrder r)
|
||||
{
|
||||
switch (r)
|
||||
{
|
||||
case rOrder_ZYX: return rOrder_XYZ;
|
||||
case rOrder_YZX: return rOrder_XZY;
|
||||
case rOrder_ZXY: return rOrder_YXZ;
|
||||
case rOrder_XZY: return rOrder_YZX;
|
||||
case rOrder_YXZ: return rOrder_ZXY;
|
||||
case rOrder_XYZ: return rOrder_ZYX;
|
||||
default: return rOrder_Default;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
float Math::Sqrt(float v)
|
||||
{ return sqrtf(v); }
|
||||
|
||||
float Math::TestEqual(float a, float b, float e)
|
||||
{ return Types::Abs(b - a) < e ? true : false; }
|
||||
bool Math::EqualZero(float v, float e)
|
||||
{ return (v < -e) || (v > e) ? false : true; }
|
||||
|
||||
float Math::Pow(float v, float e)
|
||||
{ return pow(v, e); }
|
||||
|
||||
float Math::Ceil(float v)
|
||||
{ return (v < 0) ? (float)((int)v) : (float)((int)(v + 1)); }
|
||||
float Math::Floor(float v)
|
||||
{ return (v < 0) ? (float)((int)(v - 1)) : (float)((int)v); }
|
||||
float Math::Mod(float v)
|
||||
{
|
||||
double integral;
|
||||
return (float)modf(v, &integral);
|
||||
}
|
||||
float Math::RangeAdjust(float v, float old_min, float old_max, float new_min, float new_max)
|
||||
{ return Types::Clamp((v - old_min) / (old_max - old_min) * (new_max - new_min) + new_min, new_min, new_max); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Math::IsFinite(float v) { return (v <= FLT_MAX && v >= -FLT_MAX); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#define __USE_LUT_BASED_TRIG__ 0
|
||||
|
||||
#if (__USE_LUT_BASED_TRIG__ == 0)
|
||||
|
||||
void Math::Init() {}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
float Math::Quantize(float v, float q) { return Floor(v / q) * q; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
float Math::Sin(float v) { return sin(v); }
|
||||
float Math::ASin(float v) { return asin(Types::Clamp(v, -1.f, 1.f)); }
|
||||
float Math::Cos(float v) { return cos(v); }
|
||||
float Math::ACos(float v) { return acos(Types::Clamp(v, -1.f, 1.f)); }
|
||||
float Math::Tan(float v) { return tan(v); }
|
||||
float Math::ATan(float v) { return atan(v); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#else
|
||||
|
||||
#include "container/narray.h"
|
||||
|
||||
// keep as power of 2
|
||||
#define __LUT_PRECISION 64
|
||||
|
||||
static nArray <float> lCos, lSin, lTan, lACos, lASin, lAtan;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Math::Init()
|
||||
{
|
||||
lCos.Allocate(__LUT_PRECISION);
|
||||
lSin.Allocate(__LUT_PRECISION);
|
||||
lTan.Allocate(__LUT_PRECISION);
|
||||
lACos.Allocate(__LUT_PRECISION);
|
||||
lASin.Allocate(__LUT_PRECISION);
|
||||
|
||||
for (int v = 0; v < __LUT_PRECISION; ++v)
|
||||
{
|
||||
const float deg = ((float)v / __LUT_PRECISION) * (Pi * 2.f);
|
||||
|
||||
lSin[v] = sin(deg);
|
||||
lCos[v] = cos(deg);
|
||||
lTan[v] = tan(deg);
|
||||
|
||||
const float inv = ((float)v / __LUT_PRECISION) * 2.f - 1.f;
|
||||
|
||||
lASin[v] = asin(inv);
|
||||
lACos[v] = acos(inv);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
float Math::Sin(float v)
|
||||
{ return lSin[int(v * (__LUT_PRECISION / (Pi * 2.f))) & (__LUT_PRECISION - 1)]; }
|
||||
float Math::ASin(float v)
|
||||
{ return lASin[int((v + 1.f) * (__LUT_PRECISION / 2)) & (__LUT_PRECISION - 1)]; }
|
||||
float Math::Cos(float v)
|
||||
{ return lCos[int(v * (__LUT_PRECISION / (Pi * 2.f))) & (__LUT_PRECISION - 1)]; }
|
||||
float Math::ACos(float v)
|
||||
{ return lACos[int((v + 1.f) * (__LUT_PRECISION / 2)) & (__LUT_PRECISION - 1)]; }
|
||||
float Math::Tan(float v)
|
||||
{ return lTan[int(v * (__LUT_PRECISION / (Pi * 2.f))) & (__LUT_PRECISION - 1)]; }
|
||||
float Math::ATan(float v)
|
||||
{ return atan(v); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
63
include/platform/memory/endian.cpp
Normal file
63
include/platform/memory/endian.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "memory/endian.h"
|
||||
#include "platform_config.h"
|
||||
#include "log/log.h"
|
||||
|
||||
|
||||
namespace GS {
|
||||
namespace Endian {
|
||||
|
||||
static Config g_host_endian = Undefined;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void SwapBytes(void *in_p, size_t n)
|
||||
{
|
||||
if (n == 1)
|
||||
return;
|
||||
|
||||
__ASSERT__(!(n & 1));
|
||||
|
||||
char *p = (char *)in_p;
|
||||
for (size_t c = 0; c < n / 2; ++c)
|
||||
{
|
||||
char tmp = p[c];
|
||||
p[c] = p[n - c - 1];
|
||||
p[n - c - 1] = tmp;
|
||||
}
|
||||
}
|
||||
Config GetHostConfiguration()
|
||||
{
|
||||
if (g_host_endian == Undefined)
|
||||
{
|
||||
union
|
||||
{
|
||||
uint i;
|
||||
char c[4];
|
||||
} bint = { 0x01020304 };
|
||||
|
||||
g_host_endian = bint.c[0] == 1 ? Big : Little;
|
||||
|
||||
if (g_host_endian == Big)
|
||||
__LOG__ << "Memory configuration: Big endian.\n";
|
||||
else __LOG__ << "Memory configuration: Little endian.\n";
|
||||
}
|
||||
return g_host_endian;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void *ToHost(void *p, size_t size, Config source_endian)
|
||||
{
|
||||
if (GetHostConfiguration() != source_endian)
|
||||
SwapBytes(p, size);
|
||||
return p;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
}
|
||||
116
include/platform/memory/memory.cpp
Normal file
116
include/platform/memory/memory.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include "memory/memory.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uchar Memory::GetBitCount(int v)
|
||||
{
|
||||
uchar n;
|
||||
for (n = 0; v; ++n)
|
||||
v &= (v - 1);
|
||||
return n;
|
||||
}
|
||||
uchar Memory::GetShiftCount(int v)
|
||||
{
|
||||
uchar n;
|
||||
for (n = 0; !(v & 1) && (n < 32); ++n)
|
||||
v >>= 1;
|
||||
return n;
|
||||
}
|
||||
uchar Memory::CountSetBit(int v)
|
||||
{
|
||||
uchar count = 0;
|
||||
for (int n = 0; n < 32; ++n)
|
||||
{
|
||||
count += v & 1;
|
||||
v >>= 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Memory::WriteBit(uchar *mem , uint bitoffset, uint bitcount, uint v)
|
||||
{
|
||||
mem += bitoffset >> 3;
|
||||
bitoffset &= 7;
|
||||
|
||||
while (bitcount--)
|
||||
{
|
||||
mem[0] |= ((v >> bitcount) & 1) << bitoffset;
|
||||
|
||||
if (bitoffset == 7)
|
||||
{
|
||||
bitoffset = 0;
|
||||
mem++;
|
||||
}
|
||||
else
|
||||
++bitoffset;
|
||||
}
|
||||
}
|
||||
uint Memory::ReadBit(uchar *base, uint offsetbit, uint nbit)
|
||||
{
|
||||
base += offsetbit >> 3;
|
||||
offsetbit &= 7;
|
||||
|
||||
uint v = 0;
|
||||
while (nbit--)
|
||||
{
|
||||
v += v;
|
||||
if (base[0] & (1 << offsetbit))
|
||||
v |= 1;
|
||||
if (offsetbit == 7) {offsetbit = 0; base++;} else offsetbit++;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Memory::Compare(const void *a, const void *b, size_t n)
|
||||
{
|
||||
if (!a || !b)
|
||||
return true;
|
||||
|
||||
// 8 bit padding.
|
||||
uchar *ba = (uchar *)a, *bb = (uchar *)b;
|
||||
for (uint c = n & 3; c; --c)
|
||||
if (*ba++ != *bb++)
|
||||
return true;
|
||||
|
||||
// 32 bit compare.
|
||||
uint *la = (uint *)ba, *lb = (uint *)bb;
|
||||
for (uint l = n >> 2; l; --l)
|
||||
if (*la++ != *lb++)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
void Memory::Copy(void *d, const void *s, size_t n)
|
||||
{ memcpy(d, s, n); }
|
||||
void Memory::Set(void *a, char v, size_t s)
|
||||
{ memset(a, v, s); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Memory::Fill(void *p, const char *pattern, size_t s)
|
||||
{
|
||||
size_t p_l = 0;
|
||||
for ( ; pattern[p_l] != 0; ++p_l) {}
|
||||
|
||||
char *out = (char *)p;
|
||||
for (; s >= p_l; s -= p_l)
|
||||
{
|
||||
Copy((void *)out, pattern, p_l);
|
||||
out += p_l;
|
||||
}
|
||||
Copy((void *)out, pattern, s);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
22
include/platform/network/network_interface.cpp
Normal file
22
include/platform/network/network_interface.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "network/network_interface.h"
|
||||
#include "nstring/nstring.h"
|
||||
|
||||
using namespace GS::Network;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool INetwork::SendString(void *peer, const GS::String &s)
|
||||
{
|
||||
return Send(peer, (void *)s.c_str(), (size_t)(s.Len() + 1));
|
||||
}
|
||||
bool INetwork::BroadcastString(const GS::String &s)
|
||||
{
|
||||
return Broadcast((void *)s.c_str(), (size_t)(s.Len() + 1));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
1310
include/platform/nstring/nstring.cpp
Normal file
1310
include/platform/nstring/nstring.cpp
Normal file
File diff suppressed because it is too large
Load Diff
79
include/platform/platform.cpp
Normal file
79
include/platform/platform.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "platform.h"
|
||||
#include "async/job.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "filesystem/io_base.h"
|
||||
#include "input/input_system.h"
|
||||
#include "licensing/licensing.h"
|
||||
#include "analytics/analytics.h"
|
||||
#include "billing/billing.h"
|
||||
#include "log/file_log.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
#define __ENABLE_PLATFORM_TRACE 0
|
||||
|
||||
template<> Platform *Singleton <Platform> ::i = NULL;
|
||||
String Platform::app_dir;
|
||||
|
||||
static int g_start_clock = 0;
|
||||
static Time g_start_time;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Platform::Trace(const char *trace, const char *source, int line)
|
||||
{
|
||||
#if __ENABLE_PLATFORM_TRACE
|
||||
static FileLog platform_trace("c:/platform_trace.log");
|
||||
platform_trace << trace << "(" << source << "@" << line << ")\n";
|
||||
#endif
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
String Platform::GetAppPluginPath(const char *plugin) const
|
||||
{ return ((app_dir + "/") + plugin).CleanFilePath(); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uint Types::getPOT(uint v)
|
||||
{ uint n = 1; for (; n < v; n *= 2) {} return n; }
|
||||
bool Types::isPOT(uint v)
|
||||
{ return ((v != 0) && ((v & (~v + 1)) == v)); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int Platform::GetStartClock() const
|
||||
{ return g_start_clock; }
|
||||
Time Platform::GetStartTime() const
|
||||
{ return g_start_time; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Platform::Initialize()
|
||||
{
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
g_start_clock = GetClock();
|
||||
g_start_time = GetTime();
|
||||
|
||||
job_manager->CreateJobThreadPool(Types::Max(GetSystemCoreCount() - 1, 1)); // keep 1 core for the master thread
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Platform::Platform() : initialized(false)
|
||||
{
|
||||
io = new IO::Filesystem;
|
||||
job_manager = new ASync::JobManager;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
69
include/platform/rand/rand.cpp
Normal file
69
include/platform/rand/rand.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "rand/rand.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
#define __USE_CUSTOM_RAND 1
|
||||
|
||||
static uint high = 0xDEADBEEF, low = high ^ 0x49616E42;
|
||||
static uint _rg_pn = 0;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Random::Seed(uint s)
|
||||
{
|
||||
#if __USE_CUSTOM_RAND
|
||||
high = 0xDEADBEEF;
|
||||
low = high ^ 0x49616E42;
|
||||
for (uint n = 0; n < (s & 0x1fff); ++n)
|
||||
Rand(1);
|
||||
#else
|
||||
srand(s);
|
||||
#endif
|
||||
}
|
||||
uint Random::Rand(uint r)
|
||||
{
|
||||
if (!r)
|
||||
return 0;
|
||||
#if __USE_CUSTOM_RAND
|
||||
high = (high << 16) + (high >> 16);
|
||||
high += low;
|
||||
low += high;
|
||||
return high % r;
|
||||
#else
|
||||
return rand() % r;
|
||||
#endif
|
||||
}
|
||||
float Random::FRand(float r)
|
||||
{
|
||||
return (float)Rand(65536) * r / 65536.0f;;
|
||||
}
|
||||
float Random::FRRand(float lo, float hi)
|
||||
{
|
||||
const float v = (float)(Rand(65536)) / 65536.0f;
|
||||
return v * (hi - lo) + lo;
|
||||
}
|
||||
uint Random::CRand(uint r)
|
||||
{
|
||||
uint it;
|
||||
uint _rg_cn = 0;
|
||||
|
||||
if (!r)
|
||||
return 0;
|
||||
|
||||
it = 4;
|
||||
while (it--)
|
||||
{
|
||||
_rg_cn = Rand(r);
|
||||
if (_rg_cn != _rg_pn)
|
||||
break;
|
||||
}
|
||||
_rg_pn = _rg_cn;
|
||||
return _rg_cn;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
2
include/platform/readme.txt
Normal file
2
include/platform/readme.txt
Normal file
@ -0,0 +1,2 @@
|
||||
GS framework core source files.
|
||||
This project compiles with no other dependency than stdlib.
|
||||
29
include/platform/reflection/nenum_string.cpp
Normal file
29
include/platform/reflection/nenum_string.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "reflection/nenum_string.h"
|
||||
#include "nstring/nstring.h"
|
||||
|
||||
using namespace GS::Reflection;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const char *Enum::toString(int v, Dict *dict)
|
||||
{
|
||||
for (int n = 0; dict[n].string_v; ++n)
|
||||
if (dict[n].enum_v == v)
|
||||
return dict[n].string_v;
|
||||
return 0;
|
||||
}
|
||||
int Enum::fromString(const char *s, Dict *dict)
|
||||
{
|
||||
GS::String string_v(s);
|
||||
for (int n = 0; dict[n].string_v; ++n)
|
||||
if (string_v == dict[n].string_v)
|
||||
return dict[n].enum_v;
|
||||
return -1;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
0
include/platform/social/social.cpp
Normal file
0
include/platform/social/social.cpp
Normal file
102
include/platform/thread/atomic_value.cpp
Normal file
102
include/platform/thread/atomic_value.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "thread/atomic_value.h"
|
||||
#include "assert/nassert.h"
|
||||
|
||||
|
||||
#if __PLATFORM_WINDOWS__
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace GS {
|
||||
namespace Threading {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int Atomic32::Inc()
|
||||
{ return (int)InterlockedIncrement((LONG volatile *)v); }
|
||||
int Atomic32::Dec()
|
||||
{ return (int)InterlockedDecrement((LONG volatile *)v); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int Atomic32::Get() const
|
||||
{ return *((int volatile *)v); }
|
||||
int Atomic32::Set(int _v)
|
||||
{ return InterlockedExchange((LONG volatile *)v, _v); }
|
||||
int Atomic32::Cas(int cmp, int _v)
|
||||
{ return InterlockedCompareExchange((LONG volatile *)v, _v, cmp); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Atomic32::Atomic32(int _v)
|
||||
{
|
||||
v = _aligned_malloc(sizeof(LONG), 4);
|
||||
__ASSERT__(v != NULL);
|
||||
Set(_v);
|
||||
}
|
||||
Atomic32::~Atomic32()
|
||||
{ _aligned_free(v); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#elif (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 1)) // use >GCC4.1 builtins
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
namespace GS {
|
||||
namespace Threading {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int Atomic32::Inc()
|
||||
{ return __sync_fetch_and_add((long volatile *)v, 1) + 1; }
|
||||
int Atomic32::Dec()
|
||||
{ return __sync_fetch_and_add((long volatile *)v, -1) - 1; }
|
||||
int Atomic32::Get() const
|
||||
{ return *((int volatile *)v); }
|
||||
int Atomic32::Set(int _v)
|
||||
{ return __sync_lock_test_and_set((long volatile *)v, _v); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int Atomic32::Cas(int cmp, int _v)
|
||||
{ return __sync_val_compare_and_swap((long volatile *)v, cmp, _v); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Atomic32::Atomic32(int _v)
|
||||
{
|
||||
v = memalign(4, sizeof(long));
|
||||
__ASSERT__(v != NULL);
|
||||
*(long *)v = _v;
|
||||
}
|
||||
Atomic32::~Atomic32()
|
||||
{ free(v); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
namespace GS {
|
||||
namespace Threading {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int Atomic32::Get() const
|
||||
{ __ASSERT(true); }
|
||||
int Atomic32::Set(int _v)
|
||||
{ __ASSERT(true); }
|
||||
int Atomic32::Cas(int cmp, int _v)
|
||||
{ __ASSERT(true); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
90
include/platform/thread/mutex.cpp
Normal file
90
include/platform/thread/mutex.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "thread/mutex.h"
|
||||
#include "alloc/ialloc.h"
|
||||
|
||||
using namespace GS::Threading;
|
||||
|
||||
|
||||
#if __PLATFORM_WINDOWS__
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Mutex::TryLock()
|
||||
{ return asbool(TryEnterCriticalSection((LPCRITICAL_SECTION)mutex)); }
|
||||
void Mutex::Lock()
|
||||
{
|
||||
if (mutex)
|
||||
EnterCriticalSection((LPCRITICAL_SECTION)mutex);
|
||||
}
|
||||
void Mutex::Unlock()
|
||||
{
|
||||
if (mutex)
|
||||
LeaveCriticalSection((LPCRITICAL_SECTION)mutex);
|
||||
}
|
||||
Mutex::Mutex()
|
||||
{
|
||||
mutex = new CRITICAL_SECTION;
|
||||
InitializeCriticalSection((LPCRITICAL_SECTION)mutex);
|
||||
}
|
||||
Mutex::~Mutex()
|
||||
{
|
||||
DeleteCriticalSection((LPCRITICAL_SECTION)mutex);
|
||||
_safe_delete(mutex);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#elif __PLATFORM_POSIX__
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Mutex::TryLock()
|
||||
{ return pthread_mutex_trylock(&mutex) != EBUSY ? true : false; }
|
||||
void Mutex::Lock()
|
||||
{ pthread_mutex_lock(&mutex); }
|
||||
void Mutex::Unlock()
|
||||
{ pthread_mutex_unlock(&mutex); }
|
||||
Mutex::Mutex()
|
||||
{ pthread_mutex_init(&mutex, NULL); }
|
||||
Mutex::~Mutex()
|
||||
{ pthread_mutex_destroy(&mutex); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#elif __PLATFORM_NINTENDO_WII__
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Mutex::TryLock()
|
||||
{ return OSTryLockMutex(&mutex); }
|
||||
void Mutex::Lock()
|
||||
{ OSLockMutex(&mutex); }
|
||||
void Mutex::Unlock()
|
||||
{ OSUnlockMutex(&mutex); }
|
||||
Mutex::Mutex()
|
||||
{ OSInitMutex(&mutex); }
|
||||
Mutex::~Mutex()
|
||||
{}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#else
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Mutex::TryLock()
|
||||
{ return true; }
|
||||
void Mutex::Lock()
|
||||
{}
|
||||
void Mutex::Unlock()
|
||||
{}
|
||||
Mutex::Mutex()
|
||||
{}
|
||||
Mutex::~Mutex()
|
||||
{}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
230
include/platform/thread/thread.cpp
Normal file
230
include/platform/thread/thread.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#if __PLATFORM_WINDOWS__
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <process.h>
|
||||
#elif __PLATFORM_POSIX__
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include "thread/thread.h"
|
||||
#include "assert/nassert.h"
|
||||
#include "log/log.h"
|
||||
#include <processthreadsapi.h>
|
||||
#include <string>
|
||||
|
||||
|
||||
#if __PLATFORM_WINDOWS__
|
||||
|
||||
namespace GS {
|
||||
namespace Threading {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static unsigned __stdcall win32_thread_entrypoint(void *parm)
|
||||
{
|
||||
Thread *t = (Thread *)parm;
|
||||
__ASSERT__(t != NULL);
|
||||
t->Execute();
|
||||
return 1;
|
||||
}
|
||||
void Thread::Join()
|
||||
{
|
||||
if (handle != 0)
|
||||
{
|
||||
WaitForSingleObject((HANDLE)handle, INFINITE);
|
||||
|
||||
CloseHandle((HANDLE)handle);
|
||||
handle = 0;
|
||||
}
|
||||
}
|
||||
bool Thread::Start()
|
||||
{
|
||||
handle = (void *)_beginthreadex(NULL, 0, &win32_thread_entrypoint, (void *)this, 0, NULL);
|
||||
return handle != 0;
|
||||
}
|
||||
bool Thread::SetPriority(int)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void Thread::Kill()
|
||||
{
|
||||
if (handle != 0)
|
||||
{
|
||||
CloseHandle((HANDLE)handle);
|
||||
handle = 0;
|
||||
}
|
||||
}
|
||||
void Thread::SetName(const char *name)
|
||||
{
|
||||
if (name == nullptr)
|
||||
return;
|
||||
|
||||
// Conversion UTF-8 (ou ANSI selon votre projet) vers UTF-16
|
||||
int length = MultiByteToWideChar(CP_UTF8, 0, name, -1, nullptr, 0);
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
std::wstring wname(length, L'\0');
|
||||
MultiByteToWideChar(CP_UTF8, 0, name, -1, &wname[0], length);
|
||||
|
||||
SetThreadDescription(GetCurrentThread(), wname.c_str());
|
||||
}
|
||||
void Thread::Switch()
|
||||
{ SwitchToThread(); }
|
||||
|
||||
Thread::Thread()
|
||||
{ handle = 0; }
|
||||
Thread::~Thread()
|
||||
{ Kill(); }
|
||||
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#elif __PLATFORM_EMSCRIPTEN__
|
||||
|
||||
namespace GS {
|
||||
namespace Threading {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void *pthread_execute(void *parm)
|
||||
{ return NULL; }
|
||||
void Thread::Join()
|
||||
{}
|
||||
bool Thread::Start()
|
||||
{ return false; }
|
||||
bool Thread::SetPriority(int priority)
|
||||
{ return false; }
|
||||
void Thread::Kill()
|
||||
{}
|
||||
void Thread::SetName(const char *)
|
||||
{}
|
||||
void Thread::Switch()
|
||||
{}
|
||||
Thread::Thread()
|
||||
{}
|
||||
Thread::~Thread()
|
||||
{}
|
||||
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#elif __PLATFORM_POSIX__
|
||||
|
||||
namespace GS {
|
||||
namespace Threading {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void *pthread_execute(void *parm)
|
||||
{
|
||||
Thread *t = (Thread * const)parm;
|
||||
t->Execute();
|
||||
return NULL;
|
||||
}
|
||||
void Thread::Join()
|
||||
{
|
||||
pthread_join(*((pthread_t *)handle), NULL);
|
||||
}
|
||||
bool Thread::Start()
|
||||
{
|
||||
if (!(handle = (void *)new pthread_t))
|
||||
return false;
|
||||
return pthread_create((pthread_t *)handle, NULL, pthread_execute, this) == 0;
|
||||
}
|
||||
bool Thread::SetPriority(int priority)
|
||||
{
|
||||
#ifdef EMSCRIPTEN
|
||||
return false;
|
||||
#else
|
||||
if (!handle)
|
||||
return false;
|
||||
|
||||
sched_param param;
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.sched_priority = priority;
|
||||
|
||||
return asbool(pthread_setschedparam(*((pthread_t *)handle), SCHED_OTHER, ¶m) == 0);
|
||||
#endif
|
||||
}
|
||||
void Thread::Kill()
|
||||
{
|
||||
#if __PLATFORM_ANDROID_NDK__
|
||||
__ASSERT_MSG__(true, "Android NDK cannot kill a thread.");
|
||||
#else
|
||||
if (handle)
|
||||
pthread_cancel(*((pthread_t *)handle));
|
||||
|
||||
delete (pthread_t *)handle;
|
||||
handle = NULL;
|
||||
#endif
|
||||
}
|
||||
void Thread::SetName(const char *)
|
||||
{}
|
||||
void Thread::Switch()
|
||||
{ sched_yield(); }
|
||||
Thread::Thread()
|
||||
{ handle = NULL; }
|
||||
Thread::~Thread()
|
||||
{ delete (pthread_t *)handle; }
|
||||
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#elif __PLATFORM_NINTENDO_WII__
|
||||
|
||||
namespace GS {
|
||||
namespace Threading {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void *__OSthread_wii_execute(void *parm)
|
||||
{
|
||||
nThread *t = (nThread * const)parm;
|
||||
t->alive.Set(1);
|
||||
return (void *)(t->Execute() ? 1 : 0);
|
||||
}
|
||||
void Thread::Join()
|
||||
{
|
||||
void *rv;
|
||||
if (alive.Get())
|
||||
OSJoinThread(&thread, &rv);
|
||||
alive.Set(0);
|
||||
}
|
||||
void Thread::Resume()
|
||||
{
|
||||
if (alive.Get())
|
||||
OSResumeThread(&thread);
|
||||
}
|
||||
void Thread::Suspend()
|
||||
{
|
||||
if (alive.Get())
|
||||
OSSuspendThread(&thread);
|
||||
}
|
||||
bool Thread::Start()
|
||||
{ return OSCreateThread(&thread, &__OSthread_wii_execute, this, thread_stack + 32768, 32768, 20, 0); }
|
||||
bool Thread::SetPriority(int priority)
|
||||
{ return alive.Get() ? OSSetThreadPriority(&thread, priority) : false; }
|
||||
void Thread::Kill()
|
||||
{
|
||||
if (alive.Get())
|
||||
OSCancelThread(&thread);
|
||||
alive.Set(0);
|
||||
}
|
||||
void Thread::SetName(const char *)
|
||||
{}
|
||||
Thread::Thread()
|
||||
{}
|
||||
Thread::~Thread()
|
||||
{ Kill(); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
120
include/platform/thread/thread_event.cpp
Normal file
120
include/platform/thread/thread_event.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "thread/thread_event.h"
|
||||
#include "time/ntime.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::Threading;
|
||||
|
||||
|
||||
#if __PLATFORM_WINDOWS__
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Event::Wait(Time *t)
|
||||
{ WaitForSingleObject((HANDLE)event, t ? DWORD(t->toMs()) : INFINITE); }
|
||||
void Event::Trigger()
|
||||
{ SetEvent((HANDLE)event); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Event::Event()
|
||||
{ event = (void *)CreateEvent(NULL, false, false, NULL); }
|
||||
Event::~Event()
|
||||
{ if (event) CloseHandle(event); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#elif __PLATFORM_EMSCRIPTEN__
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Event::Wait(Time *t)
|
||||
{}
|
||||
void Event::Trigger()
|
||||
{}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Event::Event()
|
||||
{}
|
||||
Event::~Event()
|
||||
{}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#elif __PLATFORM_POSIX__
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
struct pthread_event
|
||||
{
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
bool triggered;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Event::Wait(Time *t)
|
||||
{
|
||||
pthread_event *ev = (pthread_event *)event;
|
||||
|
||||
timespec time;
|
||||
|
||||
if (t)
|
||||
{
|
||||
timeval ctime;
|
||||
gettimeofday(&ctime, NULL);
|
||||
time.tv_sec = t->getSec() + ctime.tv_sec;
|
||||
time.tv_nsec = t->getNanoSec() + ctime.tv_usec * 1000;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&ev->mutex);
|
||||
while (!ev->triggered)
|
||||
{
|
||||
if (!t)
|
||||
pthread_cond_wait(&ev->cond, &ev->mutex);
|
||||
else
|
||||
if (pthread_cond_timedwait(&ev->cond, &ev->mutex, &time) == ETIMEDOUT)
|
||||
break;
|
||||
}
|
||||
ev->triggered = false;
|
||||
pthread_mutex_unlock(&ev->mutex);
|
||||
}
|
||||
void Event::Trigger()
|
||||
{
|
||||
pthread_event *ev = (pthread_event *)event;
|
||||
|
||||
pthread_mutex_lock(&ev->mutex);
|
||||
ev->triggered = true;
|
||||
pthread_cond_signal(&ev->cond);
|
||||
pthread_mutex_unlock(&ev->mutex);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Event::Event()
|
||||
{
|
||||
pthread_event *ev = new pthread_event;
|
||||
event = (void *)ev;
|
||||
|
||||
pthread_mutex_init(&ev->mutex, 0);
|
||||
pthread_cond_init(&ev->cond, 0);
|
||||
ev->triggered = false;
|
||||
}
|
||||
Event::~Event()
|
||||
{
|
||||
pthread_event *ev = (pthread_event *)event;
|
||||
pthread_mutex_destroy(&ev->mutex);
|
||||
pthread_cond_destroy(&ev->cond);
|
||||
delete ev;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
125
include/platform/time/ntime.cpp
Normal file
125
include/platform/time/ntime.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include "time/ntime.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
Time Time::Inf(std::numeric_limits <int> ::max());
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Time::operator += (const Time &b)
|
||||
{
|
||||
sec += b.sec;
|
||||
nsec += b.nsec;
|
||||
Normalize();
|
||||
}
|
||||
void Time::operator -= (const Time &b)
|
||||
{
|
||||
sec -= b.sec;
|
||||
nsec -= b.nsec;
|
||||
Normalize();
|
||||
}
|
||||
Time Time::operator + (const Time &b) const
|
||||
{ return Time(sec + b.sec, nsec + b.nsec); }
|
||||
Time Time::operator - (const Time &b) const
|
||||
{ return Time(sec - b.sec, nsec - b.nsec); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Time::operator == (const Time &b) const
|
||||
{ return (sec == b.sec) && (nsec == b.nsec); }
|
||||
bool Time::operator != (const Time &b) const
|
||||
{ return (sec != b.sec) || (nsec != b.nsec); }
|
||||
bool Time::operator > (const Time &b) const
|
||||
{ return (sec > b.sec) || ((sec == b.sec) && (nsec > b.nsec)); }
|
||||
bool Time::operator < (const Time &b) const
|
||||
{ return (sec < b.sec) || ((sec == b.sec) && (nsec < b.nsec)); }
|
||||
bool Time::operator >= (const Time &b) const
|
||||
{ return (*this > b) || (*this == b); }
|
||||
bool Time::operator <= (const Time &b) const
|
||||
{ return (*this < b) || (*this == b); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
float Time::toDay() const
|
||||
{ return toHour() / 24.f; }
|
||||
float Time::toHour() const
|
||||
{ return toMin() / 60.f; }
|
||||
float Time::toMin() const
|
||||
{ return toSec() / 60.f; }
|
||||
float Time::toSec() const
|
||||
{ return sec + nsec / 1000000000.f; }
|
||||
float Time::toMs() const
|
||||
{ return sec * 1000.f + nsec / 1000000.f; }
|
||||
float Time::toNs() const
|
||||
{ return sec * 1000000000.f + nsec; }
|
||||
String Time::toString() const
|
||||
{ return String::Format("%02d:%02d:%02d:%03d", int(toHour()) % 60, int(toMin()) % 60, int(toSec()) % 60, int(toMs()) % 1000); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Time::setSec(int s)
|
||||
{ sec = s; nsec = 0; }
|
||||
void Time::setSec(float s)
|
||||
{
|
||||
double integral, fractional = modf(s, &integral);
|
||||
sec = int(integral); nsec = int(fractional * 1000000000.0);
|
||||
Normalize();
|
||||
}
|
||||
void Time::setMs(int m)
|
||||
{
|
||||
sec = m / 1000; nsec = (m - sec * 1000) * 1000000;
|
||||
}
|
||||
void Time::setNs(int n)
|
||||
{
|
||||
sec = 0; nsec = n;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Time Time::fromSec(float s)
|
||||
{
|
||||
double integral, fractional = modf(s, &integral);
|
||||
return Time(int(integral), int(fractional * 1000000000.0));
|
||||
}
|
||||
Time Time::fromSec(int s)
|
||||
{ return Time(s); }
|
||||
Time Time::fromMs(int m)
|
||||
{ return Time(0, m * 1000000); }
|
||||
Time Time::fromNs(int n)
|
||||
{ return Time(0, n); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Time Time::Abs() const
|
||||
{ return Time(Types::Abs(sec), nsec); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Time::Normalize()
|
||||
{
|
||||
for (; nsec >= 1000000000; nsec -= 1000000000)
|
||||
sec++;
|
||||
for (; nsec < 0; nsec += 1000000000)
|
||||
sec--;
|
||||
}
|
||||
Time Time::Normalized() const
|
||||
{ return Time(sec, nsec); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Time::Time(int s, int n)
|
||||
{
|
||||
sec = s; nsec = n;
|
||||
Normalize();
|
||||
}
|
||||
Time::Time(float s)
|
||||
{ setSec(s); }
|
||||
Time::Time(int s)
|
||||
{ sec = s; nsec = 0; }
|
||||
15
include/platform/unit/nunit.cpp
Normal file
15
include/platform/unit/nunit.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "unit/nunit.h"
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
size_t GS::Units::KB(const size_t v)
|
||||
{ return v * 1024; }
|
||||
size_t GS::Units::MB(const size_t v)
|
||||
{ return v * 1024 * 1024; }
|
||||
//------------------------------------------------------------------------------
|
||||
62
include/platform/video/video_mode.cpp
Normal file
62
include/platform/video/video_mode.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include "video/video_mode.h"
|
||||
|
||||
using namespace nVideoMode;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Mode nVideoMode::mode_desc[NameLast] =
|
||||
{
|
||||
{ "CGA", 320, 200, 32, true },
|
||||
{ "QVGA", 320, 240, 32, true },
|
||||
{ "WQVGA", 480, 272, 32, true },
|
||||
{ "VGA", 640, 480, 32, true },
|
||||
{ "SVGA", 800, 600, 32, true },
|
||||
|
||||
{ "XGA", 1024, 768, 32, true },
|
||||
{ "XGAPlus", 1152, 864, 32, true },
|
||||
|
||||
{ "HD", 1366, 768, 32, true },
|
||||
{ "WXGA_922K", 1280, 720, 32, false },
|
||||
{ "WXGA_1024K", 1280, 800, 32, true },
|
||||
{ "HDPlus", 1600, 900, 32, true },
|
||||
{ "SXGA", 1280, 1024, 32, true },
|
||||
{ "WXGAPlus", 1440, 900, 32, true },
|
||||
|
||||
{ "UXGA", 1600, 1200, 32, true },
|
||||
{ "WSXGAPlus", 1680, 1050, 32, true },
|
||||
{ "FullHD", 1920, 1080, 32, false },
|
||||
{ "WUXGA", 1920, 1200, 32, true },
|
||||
|
||||
{ "QXGA", 2048, 1536, 32, true },
|
||||
{ "QWXGA", 2048, 1152, 32, true },
|
||||
{ "WQHD", 2560, 1440, 32, true },
|
||||
{ "WQXGA", 2560, 1600, 32, true }
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
AspectRatio nVideoMode::GetModeAspectRatio(const Mode &mode)
|
||||
{
|
||||
if (((mode.width * 3) / 4) == mode.height)
|
||||
return AR_4_3;
|
||||
if (((mode.width * 9) / 16) == mode.height)
|
||||
return AR_16_9;
|
||||
if (((mode.width * 10) / 16) == mode.height)
|
||||
return AR_16_10;
|
||||
|
||||
return AR_Unknown;
|
||||
}
|
||||
Mode *nVideoMode::GetMode(uint w, uint h)
|
||||
{
|
||||
for (uint n = 0; n < NameLast; ++n)
|
||||
if ((mode_desc[n].width == w) && (mode_desc[n].height == h))
|
||||
return &mode_desc[n];
|
||||
return NULL;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user