/* ----------------------------------------------------------------------------- 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 &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 &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 _h(wrapped_io->Open(path, mode)); if (_h.IsNull()) break; size_t size = _h->GetSize(); Array 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 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 _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); } //------------------------------------------------------------------------------